Home / Developers / Docs

Venue Manager API

Run the day-to-day work of a venue from your own software: bookings, payments, lockers, rentals, memberships, games, classes, students, fees and attendance. The same operations are available to AI apps as MCP tools. The API never deletes records and never changes how a product is set up; do that in Venue Manager.

Base URL https://www.sporfy.com/vm/v1

Authentication

Create a key in Venue Manager under Settings › Developers › API keys. A key is an App ID and an App Secret; send both on every request, over HTTPS, from your server only. The secret is shown once and stored hashed. A key can have Off, Read or Read & write access per product, an expiry and a list of allowed IP addresses.

curl -X GET "https://www.sporfy.com/vm/v1/spaces" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"

Plans and rate limits

API and MCP access is included from the Professional plan, product by product (Slots or Classes). Without it, keys and servers cannot be created or changed and every call answers 402. Nothing is deleted; upgrade and everything works again. Limits are per organisation, shared by every key and AI app, and can be raised with an add-on.

PlanRequests a minuteRequests a dayCalls at once
StandardNot included
Professional605,0005
Premium12015,00010
Enterprise300+50,000+25+

Every answer carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. Past a limit the answer is 429 with Retry-After in seconds; the day resets at midnight UTC.

Errors

{
  "error": {
    "code": "plan_required",
    "message": "API and MCP access needs Professional or above."
  },
  "requestId": "9f1c2ab04d7e4c5e8a31b6d0c2f47e11"
}
StatusCodeMeaning
401invalid_credentials, key_revoked, key_expiredThe key or secret is wrong, revoked or past its expiry.
402plan_requiredThe product is not on Professional or above.
403ip_not_allowed, https_requiredThe key may not be used from this address, or the request was not over https.
404unknown_tool, tool_not_allowedNo such endpoint for this key, or no such record in your organisation.
409already_marked, …The change conflicts with the current state. Nothing was changed.
422invalid_argumentsAn argument is missing or wrong. The details name the field.
429rate_limited, daily_limit_reached, too_many_concurrent_callsA rate limit was reached. Wait for Retry-After.

Security

  • A key belongs to one organisation and can never reach another organisation's data.
  • Keys and AI-app tokens work only on the endpoints in this reference. Sent anywhere else on Sporfy they are refused.
  • Use https only. Plain http is refused in production, and answers are never cached.
  • The allowed-IP list checks the address our edge saw, not an X-Forwarded-For header you send.
  • Rotate a key at any time; the old secret stops working at once. Revoke it to stop it entirely.

Connect an AI app

Create an MCP server in Settings › Developers › MCP servers, pick its tools and paste its address (https://www.sporfy.com/vm/mcp/<token>) into Claude, ChatGPT or any app that supports MCP connectors. Each person signs in and approves with OAuth 2.1 and PKCE, and the app then acts as that person: only the server's tools, only what their role allows, only while the plan includes it. Owners can see and revoke every connected app, limit who may connect by role, or regenerate the address to sign everyone out.

Classes

Attendance

List a class's attendance for a day

GET /vm/v1/classes/{class_id}/attendance

List the attendance marked for a class on one day.

Path parameters

NameTypeRequiredDescription
class_idstringYesId of the class, from classes.list.

Query parameters

NameTypeRequiredDescription
datestringYesDay, YYYY-MM-DD.

The same endpoint is offered to AI apps as the tool classes.attendance.

curl -X GET "https://www.sporfy.com/vm/v1/classes/<class_id>/attendance?date=2026-11-02" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Correct an attendance mark

PUT /vm/v1/attendance/{attendance_id}

Change an existing mark between present and absent. A session-pack student's sessions used are adjusted to match.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
attendance_idstringYesId of the attendance mark, from classes.attendance.

Body (JSON)

NameTypeRequiredDescription
presentbooleanYesThe corrected value.

The same endpoint is offered to AI apps as the tool classes.change_attendance.

curl -X PUT "https://www.sporfy.com/vm/v1/attendance/<attendance_id>" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "present": false
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Mark attendance

POST /vm/v1/classes/{class_id}/attendance

Mark students present or absent for a class on a day (and session). Nothing is written if any student is not in the class or already has a mark for that day and session; correct an existing mark with classes.change_attendance. A present mark uses one session for session-pack students.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
class_idstringYesId of the class, from classes.list.

Body (JSON)

NameTypeRequiredDescription
datestringYesDay, YYYY-MM-DD.
session_idstringNoId of the session, from classes.sessions. Required for session-based spaces.
marksobject[]YesOne entry per student.

The same endpoint is offered to AI apps as the tool classes.mark_attendance.

curl -X POST "https://www.sporfy.com/vm/v1/classes/<class_id>/attendance" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "date": "2026-11-02",
  "marks": [
    {
      "student_id": "<student_id>",
      "present": false
    }
  ]
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Classes

List batches of a class

GET /vm/v1/classes/{class_id}/batches

List the batches of a class. A student is enrolled into one batch.

Path parameters

NameTypeRequiredDescription
class_idstringYesId of the class, from classes.list.

The same endpoint is offered to AI apps as the tool classes.batches.

curl -X GET "https://www.sporfy.com/vm/v1/classes/<class_id>/batches" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Get a class

GET /vm/v1/classes/{class_id}

Get one class with its fee plans, enrolment count and batches.

Path parameters

NameTypeRequiredDescription
class_idstringYesId of the class, from classes.list.

The same endpoint is offered to AI apps as the tool classes.get.

curl -X GET "https://www.sporfy.com/vm/v1/classes/<class_id>" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

List classes

GET /vm/v1/classes

List the organisation's classes with their status, how many students are enrolled and the fee plans each offers.

Query parameters

NameTypeRequiredDescription
space_idstringNoOnly the classes run from this space, from spaces.list.
statusstringNoOnly classes with this status, for example active.
skipintegerNoClasses to skip, for paging. Default: 0.
limitintegerNoClasses to return. Default: 50.

The same endpoint is offered to AI apps as the tool classes.list.

curl -X GET "https://www.sporfy.com/vm/v1/classes" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

List a class's sessions on a day

GET /vm/v1/classes/{class_id}/sessions

List the sessions a class holds on one day, with their times, batch, instructors and status. Use a session's id when marking attendance for session-based classes.

Path parameters

NameTypeRequiredDescription
class_idstringYesId of the class, from classes.list.

Query parameters

NameTypeRequiredDescription
datestringYesDay to list, YYYY-MM-DD.

The same endpoint is offered to AI apps as the tool classes.sessions.

curl -X GET "https://www.sporfy.com/vm/v1/classes/<class_id>/sessions?date=2026-11-02" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Edit a class's description and overview

PATCH /vm/v1/classes/{class_id}/details

Change the words on an existing class: its display name, description, overview and terms and conditions. Only the fields you give are changed; give the whole new text for each (the old text is replaced, so read it first with classes.get to add to it). Fees, timings, batches, capacity and status cannot be changed here.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
class_idstringYesId of the class, from classes.list.

Body (JSON)

NameTypeRequiredDescription
display_namestringNoThe name shown to customers on the class page.
descriptionstringNoShort description shown on the class page and in listings. Plain text.
overviewstringNoThe longer 'about this class' text. Plain text.
terms_and_conditionsstringNoTerms customers accept when joining. Plain text.

The same endpoint is offered to AI apps as the tool classes.update_details.

curl -X PATCH "https://www.sporfy.com/vm/v1/classes/<class_id>/details" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Fees

Collect a student's fee

POST /vm/v1/students/{student_id}/fees

Collect one period of a student's class fee, paid now by a payment source or raised to be paid later. The amount comes from the student's fee plan on the class's price list, with tax; it cannot be set by the caller. Once paid, the student's next renewal date moves forward.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
student_idstringYesId of the student, from classes.students.

Body (JSON)

NameTypeRequiredDescription
renewal_datestringYesThe period being paid, as the student's current nextRenewalDate from classes.student, YYYY-MM-DD. Refused if the student has moved on, so a repeated call never bills the next period.
payment_sourcestringNoHow the money was received, as named in the organisation's payment sources, for example Cash or UPI. Leave out with pay_later.
pay_laterbooleanNoRaise the fee order without payment; collect it later with orders.settle. Default: false.
received_onstringNoDay the money was received, YYYY-MM-DD. Defaults to now.
send_invoicebooleanNoSend the invoice to the student on WhatsApp and email. Default: false.

The same endpoint is offered to AI apps as the tool classes.collect_fee.

curl -X POST "https://www.sporfy.com/vm/v1/students/<student_id>/fees" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "renewal_date": "2026-11-02"
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Students

Enrol a student

POST /vm/v1/classes/{class_id}/students

Enrol a person into a class and batch with a fee plan. Give an existing customer's customer_id (from customers.find), or a new person's name and mobile number (an existing customer with that number is reused). For a child, give the guardian (name, mobile, relation such as father): the guardian is created or reused, linked to the child and is the one billed. If the mobile number already belongs to a customer with a different name, nothing is written until the user confirms and you repeat with confirm true. Fails if they are already in the class or the organisation's student limit is reached. The first fee is collected with classes.collect_fee.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
class_idstringYesId of the class to join, from classes.list.

Body (JSON)

NameTypeRequiredDescription
customer_idstringNoId of an existing customer, from customers.find. Give this, or the details of a new person.
namestringNoName of a new person, for example Sham.
phonestringNoTheir mobile number. Optional for a child who has a guardian.
country_codestringNoCountry code of the mobile number, without +. Default: "91".
emailstringNo
guardianobjectNoFor a child: the parent or guardian, who is billed and messaged.
confirmbooleanNoOnly after the server reports that the mobile number or email already belongs to a customer with a different name: send the same call again with confirm true once the user says it is the same person. Default: false.
batch_idstringYesId of the batch to join, from classes.batches.
price_idstringNoId of the fee plan, from classes.get prices. It sets the fee and renewal date.

The same endpoint is offered to AI apps as the tool classes.enroll.

curl -X POST "https://www.sporfy.com/vm/v1/classes/<class_id>/students" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "batch_id": "<batch_id>"
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Change a student's status

PUT /vm/v1/students/{student_id}/status

Change a student's status, with a reason and effective date, and record it in their history. A past student is not billed; their fee plan is kept so they can rejoin.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
student_idstringYesId of the student, from classes.students or classes.enroll.

Body (JSON)

NameTypeRequiredDescription
statusstringYesNew status: active, inactive, past, suspended or blocked.
reasonstringNoReason, from the console's list for the status, for example 'Completed Course' for past.
effective_datestringNoDay the change takes effect, YYYY-MM-DD. Defaults to today.

The same endpoint is offered to AI apps as the tool classes.set_student_status.

curl -X PUT "https://www.sporfy.com/vm/v1/students/<student_id>/status" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "<status>"
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Get a student

GET /vm/v1/students/{student_id}

Get one student with their fee plan, next renewal date and remaining sessions.

Path parameters

NameTypeRequiredDescription
student_idstringYesId of the student, from classes.students or classes.enroll.

The same endpoint is offered to AI apps as the tool classes.student.

curl -X GET "https://www.sporfy.com/vm/v1/students/<student_id>" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

List students of a class

GET /vm/v1/classes/{class_id}/students

List the students in a class with their status, batch, fee plan and next renewal date.

Path parameters

NameTypeRequiredDescription
class_idstringYesId of the class, from classes.list.

Query parameters

NameTypeRequiredDescription
statusstringNoOnly students with this status: active, inactive, past, suspended or blocked.
skipintegerNoStudents to skip, for paging. Default: 0.
limitintegerNoStudents to return. Default: 100.

The same endpoint is offered to AI apps as the tool classes.students.

curl -X GET "https://www.sporfy.com/vm/v1/classes/<class_id>/students" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Customers

Customers

Find a customer

GET /vm/v1/customers

Find the organisation's existing customers by name, mobile number or email. Use the returned id as customer_id when booking, enrolling or charging, so nobody is entered twice. If nobody matches, give the new person's details to that tool instead and they are created; for a child, add a guardian.

Query parameters

NameTypeRequiredDescription
querystringYesPart of a name, a mobile number or an email address.
limitintegerNo Default: 10.

The same endpoint is offered to AI apps as the tool customers.find.

curl -X GET "https://www.sporfy.com/vm/v1/customers?query=%3Cquery%3E" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Slots

Games

Add a walk-in player

POST /vm/v1/games/{game_id}/walk-ins

Add a player who has no account to a game. Fails if the game is full or the mobile number is already on it. Payment is not taken here.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
game_idstringYesId of the game, from games.list or games.create.

Body (JSON)

NameTypeRequiredDescription
namestringYesThe walk-in's name.
mobilestringNoTheir mobile number.
emailstringNoTheir email address.
seatsintegerNoSeats they take. Default: 1.

The same endpoint is offered to AI apps as the tool games.add_walk_in.

curl -X POST "https://www.sporfy.com/vm/v1/games/<game_id>/walk-ins" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "<name>"
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Cancel a game

DELETE /vm/v1/games/{game_id}

Cancel a game and free the courts it held. Refused while players are on it, so nobody who has joined or paid is dropped without being removed first.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
game_idstringYesId of the game, from games.list or games.create.

The same endpoint is offered to AI apps as the tool games.cancel.

curl -X DELETE "https://www.sporfy.com/vm/v1/games/<game_id>" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Complete a game

POST /vm/v1/games/{game_id}/complete

Close a game that has been played so its players are recorded as having played. Safe to repeat.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
game_idstringYesId of the game, from games.list or games.create.

The same endpoint is offered to AI apps as the tool games.complete.

curl -X POST "https://www.sporfy.com/vm/v1/games/<game_id>/complete" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Create a game

POST /vm/v1/games

Create a game hosted by the organisation and block the chosen fields for its window. Fails with slot_unavailable, and creates nothing, if any of the fields is already taken during that time.

Changes data. The key needs Read & write access on the product.

Body (JSON)

NameTypeRequiredDescription
space_idstringYesId of the space hosting the game, from spaces.list.
listing_idstringYesId of the sport the game is for. It must be one of the organisation's own sports.
namestringYesName of the game.
datestringYesDay of the game, YYYY-MM-DD, on the venue's calendar.
start_timestringYesStart on the venue's clock, 24-hour HH:MM.
end_timestringYesEnd on the venue's clock, 24-hour HH:MM.
field_idsstring[]YesIds of the fields (courts) the game holds, from fields.list. Each is blocked for the window.
game_typestringNocasual, competitive, match, practice or tournament. A match always has two sides. Default: "casual".
participation_typestringNoindividual or team. Default: "individual".
max_participantsintegerNoSeats for individual games.
team_countintegerNoNumber of teams for team games.
max_participants_per_teamintegerNoPlayers per team.
cost_per_participantnumberNoPrice per player. Setting a price turns on payment.
privacystringNoPUBLIC or PRIVATE. Default: "PUBLIC".
descriptionstringNoWhat players should know.

The same endpoint is offered to AI apps as the tool games.create.

curl -X POST "https://www.sporfy.com/vm/v1/games" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "space_id": "<space_id>",
  "listing_id": "<listing_id>",
  "name": "<name>",
  "date": "2026-11-02",
  "start_time": "18:00",
  "end_time": "18:00",
  "field_ids": [
    "<field_ids>"
  ]
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Get a game

GET /vm/v1/games/{game_id}

Get one game with its schedule, price, courts held and the count of players, requests and walk-ins.

Path parameters

NameTypeRequiredDescription
game_idstringYesId of the game, from games.list or games.create.

The same endpoint is offered to AI apps as the tool games.get.

curl -X GET "https://www.sporfy.com/vm/v1/games/<game_id>" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

List games

GET /vm/v1/spaces/{space_id}/games

List the games a space hosts: upcoming, ongoing or past, with how many are playing.

Path parameters

NameTypeRequiredDescription
space_idstringYesId of the space, from spaces.list.

Query parameters

NameTypeRequiredDescription
statusstringNoupcoming, ongoing or past. Default: "upcoming".
searchstringNoOnly games whose name starts with this text.
pageintegerNoPage number, starting at 0. Default: 0.
limitintegerNoGames per page. Default: 20.

The same endpoint is offered to AI apps as the tool games.list.

curl -X GET "https://www.sporfy.com/vm/v1/spaces/<space_id>/games" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

List a game's players

GET /vm/v1/games/{game_id}/participants

List the people on a game with the given status, including walk-ins when listing those playing, with their contact details and registration answers.

Path parameters

NameTypeRequiredDescription
game_idstringYesId of the game, from games.list or games.create.

Query parameters

NameTypeRequiredDescription
statusstringNoparticipating, requested, invited or retired. Default: "participating".

The same endpoint is offered to AI apps as the tool games.participants.

curl -X GET "https://www.sporfy.com/vm/v1/games/<game_id>/participants" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Remove a walk-in player

DELETE /vm/v1/games/{game_id}/walk-ins/{walk_in_id}

Take a walk-in off a game.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
game_idstringYesId of the game, from games.list or games.create.
walk_in_idstringYesId of the walk-in, from games.participants.

The same endpoint is offered to AI apps as the tool games.remove_walk_in.

curl -X DELETE "https://www.sporfy.com/vm/v1/games/<game_id>/walk-ins/<walk_in_id>" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Mark attendance

PUT /vm/v1/games/{game_id}/attendance/{participant_id}

Record after the game whether a player or walk-in played or did not turn up.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
game_idstringYesId of the game, from games.list or games.create.
participant_idstringYesId of a player or walk-in, from games.participants.

Body (JSON)

NameTypeRequiredDescription
turned_upbooleanYesTrue if they played, false if they did not turn up.

The same endpoint is offered to AI apps as the tool games.set_attendance.

curl -X PUT "https://www.sporfy.com/vm/v1/games/<game_id>/attendance/<participant_id>" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "turned_up": false
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Mark a game full

PUT /vm/v1/games/{game_id}/full

Close a game to new players, or open it again.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
game_idstringYesId of the game, from games.list or games.create.

Body (JSON)

NameTypeRequiredDescription
is_fullbooleanYesTrue to stop new players joining, false to open the game again.

The same endpoint is offered to AI apps as the tool games.set_full.

curl -X PUT "https://www.sporfy.com/vm/v1/games/<game_id>/full" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "is_full": false
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Approve or remove a player

PUT /vm/v1/games/{game_id}/participants/{participant_id}

Approve a player who asked to join, or remove a player from the game. Any refund for a paid place is not made here.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
game_idstringYesId of the game, from games.list or games.create.
participant_idstringYesId of the player, from games.participants.

Body (JSON)

NameTypeRequiredDescription
approvebooleanYesTrue to let the player in, false to remove them from the game.

The same endpoint is offered to AI apps as the tool games.set_participant_status.

curl -X PUT "https://www.sporfy.com/vm/v1/games/<game_id>/participants/<participant_id>" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "approve": false
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Lockers

Assign a locker

POST /vm/v1/lockers/{locker_id}/assign

Give a locker to a customer for a period. Fails if the locker is blocked or already held during any of those days. The booking is recorded as unpaid, with the amount due taken from the block's price tier; use lockers.collect_payment to record the payment.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
locker_idstringYesId of the locker, from lockers.list or lockers.available.

Body (JSON)

NameTypeRequiredDescription
customerobjectYes
confirmbooleanNoOnly after the server reports that the mobile number belongs to a customer with a different name: repeat with confirm true once the user says it is the same person. Default: false.
valid_fromstringYesFirst day of the booking, YYYY-MM-DD.
valid_tostringYesLast day of the booking, YYYY-MM-DD.
price_namestringNoName of the block's price tier to charge, from lockers.list. Optional when the block has one tier or the locker is given free.

The same endpoint is offered to AI apps as the tool lockers.assign.

curl -X POST "https://www.sporfy.com/vm/v1/lockers/<locker_id>/assign" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "customer": {},
  "valid_from": "<valid_from>",
  "valid_to": "<valid_to>"
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Find free lockers

GET /vm/v1/spaces/{space_id}/lockers/available

List the lockers in a space that are free for every day from the first day to the last day, leaving out lockers that are blocked or held by someone during that period.

Path parameters

NameTypeRequiredDescription
space_idstringYesId of the space, from spaces.list.

Query parameters

NameTypeRequiredDescription
valid_fromstringYesFirst day wanted, YYYY-MM-DD.
valid_tostringYesLast day wanted, YYYY-MM-DD.
block_idstringNoOnly the lockers in this locker block.

The same endpoint is offered to AI apps as the tool lockers.available.

curl -X GET "https://www.sporfy.com/vm/v1/spaces/<space_id>/lockers/available?valid_from=%3Cvalid_from%3E&valid_to=%3Cvalid_to%3E" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Block a locker

POST /vm/v1/lockers/{locker_id}/block

Take a free locker out of use, for example for repair. Fails if someone is holding it.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
locker_idstringYesId of the locker.

The same endpoint is offered to AI apps as the tool lockers.block.

curl -X POST "https://www.sporfy.com/vm/v1/lockers/<locker_id>/block" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Record payment for a locker

POST /vm/v1/lockers/{locker_id}/payment

Record that the holder has paid for a locker, in full, by a payment source such as Cash or UPI. The amount is the block's price tier chosen when the locker was assigned or renewed, plus tax; it cannot be set by the caller. Creates the order, transaction and invoice. Fails if the locker is already paid or has no price.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
locker_idstringYesId of a held locker with an amount due, from lockers.assign or lockers.renew.

Body (JSON)

NameTypeRequiredDescription
payment_sourcestringYesHow the money was received, as named in the organisation's payment sources, for example Cash or UPI.
received_onstringNoDay the money was received, YYYY-MM-DD. Defaults to now.
send_invoicebooleanNoSend the invoice to the customer on WhatsApp and email. Default: false.

The same endpoint is offered to AI apps as the tool lockers.collect_payment.

curl -X POST "https://www.sporfy.com/vm/v1/lockers/<locker_id>/payment" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "payment_source": "<payment_source>"
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

List locker holders

GET /vm/v1/spaces/{space_id}/lockers/holders

List the customers who currently hold a locker in a space, with the period held and what they owe.

Path parameters

NameTypeRequiredDescription
space_idstringYesId of the space, from spaces.list.

The same endpoint is offered to AI apps as the tool lockers.holders.

curl -X GET "https://www.sporfy.com/vm/v1/spaces/<space_id>/lockers/holders" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

List lockers

GET /vm/v1/spaces/{space_id}/lockers

List a space's locker blocks and every locker in them, with the holder, the period held, the payment status and the price tiers each block offers.

Path parameters

NameTypeRequiredDescription
space_idstringYesId of the space, from spaces.list.

Query parameters

NameTypeRequiredDescription
block_idstringNoOnly the lockers in this locker block.
statusstringNoOnly lockers with this status: available, booked or blocked.

The same endpoint is offered to AI apps as the tool lockers.list.

curl -X GET "https://www.sporfy.com/vm/v1/spaces/<space_id>/lockers" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Release a locker

POST /vm/v1/lockers/{locker_id}/release

Take a locker back from its holder so it is free again. Refused when the booking has been paid, so a payment record is never lost.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
locker_idstringYesId of the locker.

The same endpoint is offered to AI apps as the tool lockers.release.

curl -X POST "https://www.sporfy.com/vm/v1/lockers/<locker_id>/release" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Renew a locker

POST /vm/v1/lockers/{locker_id}/renew

Extend a held locker to a later last day. Fails if the locker is not held, or if someone else has it after the current booking ends. The extension is charged at the block's price tier and left unpaid until lockers.collect_payment.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
locker_idstringYesId of a locker that is held, from lockers.list.

Body (JSON)

NameTypeRequiredDescription
valid_tostringYesThe new last day of the booking, YYYY-MM-DD. Must be after the current last day.
price_namestringNoPrice tier to charge for the extra period. Optional when the block has one tier. When given or implied, the locker becomes unpaid for that amount.

The same endpoint is offered to AI apps as the tool lockers.renew.

curl -X POST "https://www.sporfy.com/vm/v1/lockers/<locker_id>/renew" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "valid_to": "<valid_to>"
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Unblock a locker

POST /vm/v1/lockers/{locker_id}/unblock

Put a blocked locker back into use. Does nothing to a locker that is not blocked.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
locker_idstringYesId of the locker.

The same endpoint is offered to AI apps as the tool lockers.unblock.

curl -X POST "https://www.sporfy.com/vm/v1/lockers/<locker_id>/unblock" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Slot memberships

Add a member

POST /vm/v1/memberships/{membership_id}/members

Add a person to a slot membership. Give an existing customer's customer_id (from customers.find), or a new person's name and mobile number; for a child give the guardian (name, mobile, relation such as father), who is created or reused and linked. If the mobile number already belongs to a customer with a different name, nothing is written until the user confirms it is the same person and you repeat the call with confirm true. The person has no plan until you sell one with memberships.sell_plan. Fails if they are already a member of this membership, or the organisation's member limit is reached.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
membership_idstringYesId of the membership to join, from memberships.list.

Body (JSON)

NameTypeRequiredDescription
customer_idstringNoId of an existing customer, from customers.find. Give this, or the details of a new person.
namestringNoName of a new person, for example Sham.
phonestringNoTheir mobile number. Optional for a child who has a guardian.
country_codestringNoCountry code of the mobile number, without +. Default: "91".
emailstringNo
guardianobjectNoFor a child: the parent or guardian, who is billed and messaged.
confirmbooleanNoOnly after the server reports that the mobile number or email already belongs to a customer with a different name: send the same call again with confirm true once the user says it is the same person. Default: false.

The same endpoint is offered to AI apps as the tool memberships.add_member.

curl -X POST "https://www.sporfy.com/vm/v1/memberships/<membership_id>/members" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

List memberships

GET /vm/v1/spaces/{space_id}/memberships

List the slot memberships a space runs, with the plans each one sells (name, price, validity, hours) and how many members are active.

Path parameters

NameTypeRequiredDescription
space_idstringYesId of the space, from spaces.list.

The same endpoint is offered to AI apps as the tool memberships.list.

curl -X GET "https://www.sporfy.com/vm/v1/spaces/<space_id>/memberships" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Get a member

GET /vm/v1/members/{member_id}

Get one slot member with every plan they have bought, which is current and how much of it is used.

Path parameters

NameTypeRequiredDescription
member_idstringYesId of the member, from memberships.members or memberships.add_member.

The same endpoint is offered to AI apps as the tool memberships.member.

curl -X GET "https://www.sporfy.com/vm/v1/members/<member_id>" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

List members of a membership

GET /vm/v1/memberships/{membership_id}/members

List the members of a slot membership with their status and plans.

Path parameters

NameTypeRequiredDescription
membership_idstringYesId of the membership, from memberships.list.

Query parameters

NameTypeRequiredDescription
statusstringNoOnly members with this status: active, inactive or past.
skipintegerNoMembers to skip, for paging. Default: 0.
limitintegerNoMembers to return. Default: 50.

The same endpoint is offered to AI apps as the tool memberships.members.

curl -X GET "https://www.sporfy.com/vm/v1/memberships/<membership_id>/members" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Sell a plan to a member

POST /vm/v1/members/{member_id}/plans

Sell a membership plan to a member, paid now by a payment source or recorded to be paid later. The price is the plan's listed price plus tax and cannot be set by the caller. Creates the order and invoice and attaches the plan to the member; a plan bought while another still has hours left waits in the queue.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
member_idstringYesId of the member, from memberships.members or memberships.add_member.

Body (JSON)

NameTypeRequiredDescription
planstringYesName or price_id of the plan to sell, from memberships.list.
payment_sourcestringNoHow the money was received, as named in the organisation's payment sources, for example Cash or UPI. Leave out with pay_later.
pay_laterbooleanNoRecord the plan as bought but not yet paid; collect it later with orders.settle. Default: false.
start_datestringNoDay the plan starts, YYYY-MM-DD. Defaults to today.
received_onstringNoDay the money was received, YYYY-MM-DD. Defaults to now.
send_invoicebooleanNoSend the invoice to the member on WhatsApp and email. Default: false.

The same endpoint is offered to AI apps as the tool memberships.sell_plan.

curl -X POST "https://www.sporfy.com/vm/v1/members/<member_id>/plans" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "plan": "<plan>"
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Change a member's status

PUT /vm/v1/members/{member_id}/status

Mark a member active, inactive or past. Nothing is deleted; their plans and payment history stay.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
member_idstringYesId of the member.

Body (JSON)

NameTypeRequiredDescription
statusstringYesNew status: active, inactive or past.

The same endpoint is offered to AI apps as the tool memberships.set_member_status.

curl -X PUT "https://www.sporfy.com/vm/v1/members/<member_id>/status" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "<status>"
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Edit a membership's description and overview

PATCH /vm/v1/memberships/{membership_id}/details

Change the words on an existing slot membership: its description and overview, the same 'About' text the portal edits. Only what you give is changed; give the whole new text (read it first with memberships.list to add to it). Plans, prices, timings and rules cannot be changed here.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
membership_idstringYesId of the membership, from memberships.list.

Body (JSON)

NameTypeRequiredDescription
descriptionstringNoShort description shown on the membership page. Plain text.
overviewstringNoThe longer 'about this membership' text. Plain text.

The same endpoint is offered to AI apps as the tool memberships.update_details.

curl -X PATCH "https://www.sporfy.com/vm/v1/memberships/<membership_id>/details" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Orders and payments

Unpaid orders

GET /vm/v1/orders/pending

Orders raised and not yet paid, optionally for one customer by mobile number. Use it to see what a customer owes, then collect with orders.settle or send orders.payment_link.

Query parameters

NameTypeRequiredDescription
phonestringNoCustomer's mobile number, digits only, to list what they owe.
limitintegerNoMost recent first. Default: 20.

The same endpoint is offered to AI apps as the tool orders.pending.

curl -X GET "https://www.sporfy.com/vm/v1/orders/pending" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Collect payment for open orders

POST /vm/v1/orders/settle

Record that the customer has paid the outstanding amount on one or more open orders, in one payment received by a payment source such as Cash or UPI. Each order is invoiced as if paid alone. Orders that are not open for collection, or belong to another organisation, are refused.

Changes data. The key needs Read & write access on the product.

Body (JSON)

NameTypeRequiredDescription
order_idsany[]YesIds of open orders to collect together, for example the order rentals.return raised.
payment_sourcestringYesHow the money was received, as named in the organisation's payment sources.

The same endpoint is offered to AI apps as the tool orders.settle.

curl -X POST "https://www.sporfy.com/vm/v1/orders/settle" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "order_ids": [
    "<order_ids>"
  ],
  "payment_source": "<payment_source>"
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Rentals

Book or hand out rentals

POST /vm/v1/rentals/assign

Book rental products for a customer: handed over now, or booked for a time you give (date, start_time, end_time). Fails with out_of_stock if the shop does not have that many free over that time. Nothing is charged yet: the rentals are priced from the time they are out when they are returned (rentals.return).

Changes data. The key needs Read & write access on the product.

Body (JSON)

NameTypeRequiredDescription
datestringNoDay the rentals are needed, YYYY-MM-DD, to book ahead. Leave out for right now.
start_timestringNoStart on the venue's clock, 24-hour HH:MM. Needed with date.
end_timestringNoEnd on the venue's clock, 24-hour HH:MM, after start_time. Needed with date.
space_idstringYesSpace the rentals are handed out in.
customerobjectYes
confirmbooleanNoOnly after the server reports that the mobile number belongs to a customer with a different name: repeat with confirm true once the user says it is the same person. Default: false.
slot_member_idstringNoId of the customer's slot membership, when they are a member.
rentalsobject[]Yes

The same endpoint is offered to AI apps as the tool rentals.assign.

curl -X POST "https://www.sporfy.com/vm/v1/rentals/assign" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "space_id": "<space_id>",
  "customer": {},
  "rentals": [
    {
      "rental_id": "<rental_id>"
    }
  ]
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Rental stock available now

GET /vm/v1/spaces/{space_id}/rentals/available

List the rental products of a space that have stock left, with the quantity still free (total stock minus what is out or booked over the same time). Right now by default; give date, start_time and end_time to check a time you want to book.

Path parameters

NameTypeRequiredDescription
space_idstringYesId of the space (from spaces.list).

Query parameters

NameTypeRequiredDescription
datestringNoDay the rentals are needed, YYYY-MM-DD, to book ahead. Leave out for right now.
start_timestringNoStart on the venue's clock, 24-hour HH:MM. Needed with date.
end_timestringNoEnd on the venue's clock, 24-hour HH:MM, after start_time. Needed with date.

The same endpoint is offered to AI apps as the tool rentals.available.

curl -X GET "https://www.sporfy.com/vm/v1/spaces/<space_id>/rentals/available" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

List rental products

GET /vm/v1/spaces/{space_id}/rentals

List the rental products of a space with their total stock and price tiers.

Path parameters

NameTypeRequiredDescription
space_idstringYesId of the space (from spaces.list).

The same endpoint is offered to AI apps as the tool rentals.list.

curl -X GET "https://www.sporfy.com/vm/v1/spaces/<space_id>/rentals" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Rentals currently out

GET /vm/v1/spaces/{space_id}/rentals/open

List who currently has rentals out in a space (handed out in the last 48 hours and not yet returned).

Path parameters

NameTypeRequiredDescription
space_idstringYesId of the space (from spaces.list).

The same endpoint is offered to AI apps as the tool rentals.open.

curl -X GET "https://www.sporfy.com/vm/v1/spaces/<space_id>/rentals/open" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Return rentals and bill

POST /vm/v1/rentals/usage/{usage_id}/return

Take back everything a customer had out in one hand-out. The rentals are priced from the time they were out and one pending order is raised. Collect it with orders.settle. A usage can be returned only once.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
usage_idstringYesId of the open rental usage (from rentals.open or rentals.assign).

The same endpoint is offered to AI apps as the tool rentals.return.

curl -X POST "https://www.sporfy.com/vm/v1/rentals/usage/<usage_id>/return" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Bookings

Block a time

POST /vm/v1/slots/block

Take a window out of sale on a field, for example for maintenance or a private event. Fails with slot_unavailable if anything already occupies that time. Undo with slots.unblock.

Changes data. The key needs Read & write access on the product.

Body (JSON)

NameTypeRequiredDescription
field_idstringYesId of the field to book. Get it from fields.list.
datestringYesDay of the slot as YYYY-MM-DD, on the venue's calendar.
start_timestringYesStart on the venue's clock, 24-hour HH:MM.
end_timestringYesEnd on the venue's clock, 24-hour HH:MM. Must be after start_time.
time_range_config_idstringNoId of the field's time range this slot follows (from fields.list).
reasonstringNoWhy the time is blocked (shown to your staff).

The same endpoint is offered to AI apps as the tool slots.block.

curl -X POST "https://www.sporfy.com/vm/v1/slots/block" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "field_id": "<field_id>",
  "date": "2026-11-02",
  "start_time": "18:00",
  "end_time": "18:00"
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Book a slot

POST /vm/v1/slots/book

Book a window on a field for a customer, the way the console's Book slot does without taking payment: the slot is recorded as booked and unpaid. Fails with slot_unavailable if the time is taken. Needs an amount, or a time_range_config_id whose price can be used.

Changes data. The key needs Read & write access on the product.

Body (JSON)

NameTypeRequiredDescription
field_idstringYesId of the field to book. Get it from fields.list.
datestringYesDay of the slot as YYYY-MM-DD, on the venue's calendar.
start_timestringYesStart on the venue's clock, 24-hour HH:MM.
end_timestringYesEnd on the venue's clock, 24-hour HH:MM. Must be after start_time.
time_range_config_idstringNoId of the field's time range this slot follows (from fields.list).
customerobjectYes
confirmbooleanNoOnly after the server reports that the mobile number belongs to a customer with a different name: repeat with confirm true once the user says it is the same person. Default: false.
amountnumberNoPrice for the window. Defaults to the time range's own price.

The same endpoint is offered to AI apps as the tool slots.book.

curl -X POST "https://www.sporfy.com/vm/v1/slots/book" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "field_id": "<field_id>",
  "date": "2026-11-02",
  "start_time": "18:00",
  "end_time": "18:00",
  "customer": {}
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Cancel a slot

POST /vm/v1/slots/{slot_id}/cancel

Cancel a booking so the time is free again. The slot stays on record as cancelled.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
slot_idstringYesId of the slot.

The same endpoint is offered to AI apps as the tool slots.cancel.

curl -X POST "https://www.sporfy.com/vm/v1/slots/<slot_id>/cancel" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Record payment for a slot

POST /vm/v1/slots/{slot_id}/payment

Record that the customer has paid for a slot, in full, by a payment source such as Cash or UPI. The price comes from the field's time range plus tax; it cannot be set by the caller. Creates the order, transaction and invoice and links them to the slot. Fails if the slot is already paid.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
slot_idstringYesId of a booked or blocked slot that has a customer, from slots.book or slots.block.

Body (JSON)

NameTypeRequiredDescription
payment_sourcestringYesHow the money was received, as named in the organisation's payment sources, for example Cash or UPI.
received_onstringNoDay the money was received, YYYY-MM-DD. Defaults to now.
send_invoicebooleanNoSend the invoice to the customer on WhatsApp and email. Default: false.

The same endpoint is offered to AI apps as the tool slots.collect_payment.

curl -X POST "https://www.sporfy.com/vm/v1/slots/<slot_id>/payment" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "payment_source": "<payment_source>"
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Extend a slot

POST /vm/v1/slots/{slot_id}/extend

Add minutes after a booking's end, priced from the field's time range and added to the slot's unpaid order. Fails with slot_unavailable if the extra time runs into another booking. Use check_only to see the price first.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
slot_idstringYesId of the booked slot to extend.

Body (JSON)

NameTypeRequiredDescription
extra_minutesintegerYesMinutes to add after the slot's current end.
check_onlybooleanNoTrue to get the price and availability of the extension without changing anything. Default: false.
discount_percentnumberNoPercentage discount on the extension.
discount_notestringNoReason shown on the order for the discount.

The same endpoint is offered to AI apps as the tool slots.extend.

curl -X POST "https://www.sporfy.com/vm/v1/slots/<slot_id>/extend" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "extra_minutes": 1
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Get a slot

GET /vm/v1/slots/{slot_id}

Fetch one slot with its customer, status, price and payment details.

Path parameters

NameTypeRequiredDescription
slot_idstringYesId of the slot.

The same endpoint is offered to AI apps as the tool slots.get.

curl -X GET "https://www.sporfy.com/vm/v1/slots/<slot_id>" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Hold slots

POST /vm/v1/slots/hold

Reserve windows for a short time while a customer decides or pays. If any window is taken nothing is held. Release with slots.release_hold, or the hold frees itself when the minutes run out.

Changes data. The key needs Read & write access on the product.

Body (JSON)

NameTypeRequiredDescription
windowsobject[]YesThe windows to hold together. All or none are held.
minutesintegerNoHow long the hold lasts before it frees itself. Default: 7.

The same endpoint is offered to AI apps as the tool slots.hold.

curl -X POST "https://www.sporfy.com/vm/v1/slots/hold" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "windows": [
    {
      "field_id": "<field_id>",
      "date": "2026-11-02",
      "start_time": "18:00",
      "end_time": "18:00"
    }
  ]
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

List slots of a day

GET /vm/v1/spaces/{space_id}/slots

List the booked, blocked and held slots of a space on one day, optionally for one field. Free time is whatever the field's time ranges leave over; expired checkout holds are not listed.

Path parameters

NameTypeRequiredDescription
space_idstringYesId of the space (from spaces.list).

Query parameters

NameTypeRequiredDescription
datestringYesDay as YYYY-MM-DD.
field_idstringNoOnly this field's slots.

The same endpoint is offered to AI apps as the tool slots.list.

curl -X GET "https://www.sporfy.com/vm/v1/spaces/<space_id>/slots?date=2026-11-02" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Release a hold

POST /vm/v1/slots/hold/release

Give held windows back before they expire. Slots that were meanwhile paid for are left untouched.

Changes data. The key needs Read & write access on the product.

Body (JSON)

NameTypeRequiredDescription
hold_tokenstringYesThe hold_token slots.hold returned.
slot_idsstring[]YesThe slots to release.

The same endpoint is offered to AI apps as the tool slots.release_hold.

curl -X POST "https://www.sporfy.com/vm/v1/slots/hold/release" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "hold_token": "<hold_token>",
  "slot_ids": [
    "<slot_ids>"
  ]
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Reschedule a slot

POST /vm/v1/slots/{slot_id}/reschedule

Move a booking to another time on the same field. Fails with slot_unavailable if the new time is taken. When the time range changes, the slot's price follows the new range.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
slot_idstringYesId of the slot to move.

Body (JSON)

NameTypeRequiredDescription
datestringYesNew day, YYYY-MM-DD.
start_timestringYesNew start, 24-hour HH:MM.
end_timestringYesNew end, 24-hour HH:MM.
time_range_config_idstringNoThe time range the new window follows, when it changes price.

The same endpoint is offered to AI apps as the tool slots.reschedule.

curl -X POST "https://www.sporfy.com/vm/v1/slots/<slot_id>/reschedule" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "date": "2026-11-02",
  "start_time": "18:00",
  "end_time": "18:00"
}'
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Unblock a time

DELETE /vm/v1/slots/{slot_id}/block

Remove a block made with slots.block so the time can be booked again. Only blocked slots can be unblocked; a booking is cancelled with slots.cancel.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
slot_idstringYesId of the slot.

The same endpoint is offered to AI apps as the tool slots.unblock.

curl -X DELETE "https://www.sporfy.com/vm/v1/slots/<slot_id>/block" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Venues and courts

List fields of a space

GET /vm/v1/spaces/{space_id}/fields

List the bookable fields (courts, turfs, rooms) of one space, with their time ranges and prices. A time range's id is what slots.book and slots.block take as time_range_config_id.

Path parameters

NameTypeRequiredDescription
space_idstringYesId of the space (venue). Get it from spaces.list.

The same endpoint is offered to AI apps as the tool fields.list.

curl -X GET "https://www.sporfy.com/vm/v1/spaces/<space_id>/fields" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

Edit a field's description and overview

PATCH /vm/v1/fields/{field_id}/details

Change the words on an existing bookable field: its display name, description, overview and terms and conditions. Only the fields you give are changed; give the whole new text for each (read it first with fields.list to add to it). Prices, time ranges, capacity and availability cannot be changed here.

Changes data. The key needs Read & write access on the product.

Path parameters

NameTypeRequiredDescription
field_idstringYesId of the bookable field (court, turf, room), from fields.list.

Body (JSON)

NameTypeRequiredDescription
display_namestringNoThe name shown to customers.
descriptionstringNoShort description shown on the booking page. Plain text.
overviewstringNoThe longer 'about this field' text. Plain text.
terms_and_conditionsstringNoTerms customers accept when booking. Plain text.

The same endpoint is offered to AI apps as the tool fields.update_details.

curl -X PATCH "https://www.sporfy.com/vm/v1/fields/<field_id>/details" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }

List spaces

GET /vm/v1/spaces

List every space (venue) of the organisation. Use the returned ids with the other slot tools.

No arguments.

The same endpoint is offered to AI apps as the tool spaces.list.

curl -X GET "https://www.sporfy.com/vm/v1/spaces" \
  -H "X-App-Id: YOUR_APP_ID" \
  -H "X-App-Secret: YOUR_APP_SECRET"
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 9f1c2ab04d7e4c5e8a31b6d0c2f47e11
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60

{ …a JSON object with this endpoint's result… }
Book a demoStart free trial