{"openapi":"3.1.0","info":{"title":"NogPets API","version":"1.4.0","summary":"Run your pet grooming business from any AI assistant; register a pet business from anywhere; book grooming, walks and sitting in Stellenbosch.","description":"**Run your pet business** (tag Run, scope `business:manage`): the owners, managers and\nstaff of an approved NogPets business run it from their assistant. Today's day plan per\nvan or walker, bookings, clients and notes, prices, working hours, time off, service\nareas, earnings, payouts and who hasn't paid; book a phone or walk-in client, rebook,\nmove or cancel, send a client their Payfast link, and make an invoice link with a QR\ncode for any amount. Staff read their own day; owners and managers make changes.\nEvery change is logged with the assistant's name, and anything that touches bookings,\nprices, areas or money answers `CONFIRM_REQUIRED` with a summary first. Booking through\nNogPets is for South African businesses (rand, Johannesburg time); elsewhere those tools\nanswer `NOT_AVAILABLE_IN_COUNTRY` and the rest works in the business's own currency and\ntime zone.\n\n**For pet businesses, anywhere in the world** (tag Business, scope `business:write`):\na groomer, dog walker or pet sitter registers and manages their business on NogPets\nthrough their own assistant, in their own country, currency and time zone. Every\napplication is a draft until NogPets approves it.\n\n**For pet owners in Stellenbosch, South Africa**, where NogPets runs its own vans and\nwalkers: check coverage, prices and open times without signing in; with the person's\npermission, book, move, cancel and pay, and buy from the shop when it is open. A request\nwe can't serve (another town or country, or a fully booked week) is noted for a person\nat NogPets to follow up (`NO_COVERAGE` / `NO_AVAILABILITY` with `leadId` and `message`).\n\n- **The person approves money.** A card booking or order comes back with a `payUrl`\n  the person opens to pay on Payfast. Nothing here takes a card. A cash booking needs\n  `confirm: true`, sent only after the person has seen the summary and said yes.\n- **Same rules as the app.** Prices, coverage, open times and cancellation windows\n  come from the same server code; the API adds none of its own.\n- Booking money is integer cents in South African rand (ZAR): `38000` is R380. Times\n  are ISO 8601 instants; booking local time is Africa/Johannesburg (UTC+2). A business\n  application's prices are in the business's own `currency` (minor units) and its hours\n  in its own `timezone`.\n- Errors are `{\"error\": {\"code\", \"message\", \"details\"}}`; `code` is stable\n  (e.g. `NO_COVERAGE`, `SLOT_TAKEN`, `CONFIRM_REQUIRED`).\n\nReads marked public need no auth. Everything about a person needs an OAuth 2.1\naccess token (authorization code + PKCE) or a personal API key, as a Bearer token.\nThe same operations are MCP tools at `https://mcp.nogpets.com/mcp`.\n\n**Business sign-up, in order** (the first call says the `country`):\nstartBusinessSignup → addBusinessServices → setServiceArea → addResources → setOperatingHours → inviteStaff\n(optional) → connectPayfast (optional, South Africa only, merchant id only) →\ngetSignupStatus → submitBusinessForReview (`confirm: true` after the person saw the\nsummary). Every answer carries `next` and a `statusUrl` page for the person.\n","contact":{"name":"NogPets","email":"hello@nogpets.com","url":"https://nogpets.com/developers"},"termsOfService":"https://nogpets.com/terms"},"servers":[{"url":"https://api.nogpets.com","description":"Production"}],"tags":[{"name":"Run","description":"For approved pet businesses: run the business from an assistant. The day plan, bookings, clients, prices, hours, time off, areas and money, for the business's owners and managers (staff see their own day). Scope business:manage; changes that touch bookings or many clients need confirm: true after a summary."},{"name":"Services","description":"What we do, where, and for how much. Public."},{"name":"Booking","description":"Open times, booking, moving, cancelling and paying."},{"name":"Account","description":"The person's profile, pets and addresses."},{"name":"Shop","description":"Pet food, toys, beds and accessories. Only while the shop is open (else `SHOP_OFF`)."},{"name":"Directory","description":"Pet businesses in and around Stellenbosch. Public."},{"name":"Business","description":"For pet businesses anywhere in the world: register and manage a grooming, walking or sitting business on NogPets through an assistant, in its own country, currency and time zone. Scope business:write; nothing is live until NogPets approves it."}],"security":[],"paths":{"/v1/services":{"get":{"operationId":"listServices","tags":["Services"],"summary":"Service lines, services and prices","description":"Every service line (grooming, walks, pet sitting), its services with prices by pet size and coat, the card fee, and the areas we cover.","x-mcp-tool":{"name":"list_services","title":"What NogPets offers","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"Lists NogPets' services (mobile dog grooming at the door, dog walks, pet sitting) with prices and durations, the R10 card fee, whether cash is taken, and the Stellenbosch suburbs we cover.\nUse it first when the person asks what NogPets does, how much something costs, or which service to pick. Prices depend on the pet: `tiers` give the price by weight and coat (first match wins; minKg inclusive, maxKg exclusive). For an exact price for the person's pets, call get_quote.\nService `id`s are what get_quote, find_times and book take in `serviceIds`: exactly one PRIMARY service per pet plus any EXTRAs of the same line.\n"},"responses":{"200":{"description":"The catalogue","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Services"},"example":{"currency":"ZAR","serviceFeeCents":1000,"acceptsCash":true,"areas":["Stellenbosch Central","Die Boord","Paradyskloof"],"lines":[{"id":"grooming","label":"Grooming","blurb":"Our van at your door. Bath, cut and nails.","durationMode":"SUM","repeats":false,"services":[{"id":"full-groom","name":"Full groom","kind":"PRIMARY","blurb":"Bath, cut, blow-dry, nails and ears.","petTypes":["DOG"],"priceCents":38000,"durationMin":60,"fromCents":38000,"toCents":68000,"groupSize":1,"tiers":[{"coat":"LONG","maxKg":10,"priceCents":46000,"durationMin":75},{"maxKg":10,"priceCents":38000,"durationMin":60}]}]}]}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/coverage":{"get":{"operationId":"checkCoverage","tags":["Services"],"summary":"Do you come to this address?","description":"Places a typed address, a postal code or a map point in our territories and says which service lines reach it. When nothing does, `nearest` names our closest area.","x-mcp-tool":{"name":"check_coverage","title":"Check an address is covered","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"Checks whether NogPets' own vans and walkers come to an address (today: Stellenbosch, South Africa), and for which services. Give `address` as the person typed it, anywhere in the world (a Stellenbosch address with its suburb or postal code, e.g. \"12 Dorp Street, Stellenbosch Central 7600\", or a full address with town and country), or `lat` and `lng`.\nUse it before quoting or booking for a new address. `covered: false` (`NO_COVERAGE`) means we don't serve there yet: the request is noted (`leadId`) for a person at NogPets, who may follow up. Tell the person exactly `message`; follow `next`. Never promise a visit, a time or a price for an address that isn't covered.\n"},"parameters":[{"name":"address","in":"query","description":"An address as typed (with its suburb or postal code; abroad, with its town and country), or \"lat,lng\".","schema":{"type":"string","maxLength":300},"example":"14 Kromrivier Street, Die Boord, Stellenbosch 7613"},{"name":"lat","in":"query","schema":{"type":"number","minimum":-90,"maximum":90}},{"name":"lng","in":"query","schema":{"type":"number","minimum":-180,"maximum":180}},{"name":"postalCode","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9 -]{1,9}$"}}],"responses":{"200":{"description":"The answer (covered or not)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Coverage"},"examples":{"covered":{"value":{"covered":true,"place":{"suburb":"Die Boord","postalCode":"7613","lat":-33.9467,"lng":18.848},"lines":[{"id":"grooming","label":"Grooming","covered":true},{"id":"walking","label":"Walks","covered":true},{"id":"sitting","label":"Pet sitting","covered":true}],"nearest":null}},"notCovered":{"value":{"covered":false,"error":"NO_COVERAGE","place":{"suburb":null,"postalCode":"7646","lat":-33.73,"lng":18.96},"lines":[{"id":"grooming","label":"Grooming","covered":false}],"nearest":{"name":"Welgevonden","distanceKm":20.4}}},"abroad":{"value":{"covered":false,"error":"NO_COVERAGE","leadId":"hot-0c3f9a1e2b4d5c6a7e8f9a0b","message":"Thanks Sam. NogPets doesn't serve the United States yet. We've noted your request, and a person from NogPets may follow up.","next":"NogPets doesn't serve the United States yet. Tell the person that, and that we've noted their request and a person from NogPets may follow up (use `message`). Don't offer times, prices or a booking there, and don't suggest another NogPets area.","place":{"suburb":null,"postalCode":"78701","lat":30.2711,"lng":-97.7437,"town":"Austin","country":"US"},"lines":[{"id":"grooming","label":"Grooming","covered":false}],"nearest":null}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/quote":{"post":{"operationId":"getQuote","tags":["Booking"],"summary":"Price for these pets at this address","description":"The server's price and duration for one visit. Pets and address by value (no account needed), or saved ones (`addressId`, `petId`) with a token.","x-mcp-tool":{"name":"get_quote","title":"Price a visit","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"Prices one visit for the person's pets: per-pet lines, the total paying cash, the total by card (R10 card fee), and how long it takes.\nGive `category` (grooming, walking or sitting), where (`address`, or `lat`+`lng`, or `postalCode`; or a saved `addressId`), and `pets`: for each pet either a saved `petId` or its `name`, `type` (DOG/CAT), `weightKg` and `coat` (SHORT/MEDIUM/LONG), plus `serviceIds` from list_services (one PRIMARY per pet, any EXTRAs).\nNo sign-in needed for pets described by value. Quote before booking and show the person the total. Bookings are in Stellenbosch, South Africa; an address elsewhere (any country) answers 409 `NO_COVERAGE`: the request is noted for a person at NogPets; tell the person `details.message`.\n"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteRequest"},"example":{"category":"grooming","address":"14 Kromrivier Street, Die Boord 7613","pets":[{"name":"Biscuit","type":"DOG","weightKg":8,"coat":"SHORT","serviceIds":["full-groom","nails"]}]}}}},"responses":{"200":{"description":"The quote","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"},"example":{"category":"grooming","durationMin":70,"pets":[{"name":"Biscuit","items":[{"serviceId":"full-groom","name":"Full groom","kind":"PRIMARY","priceCents":38000,"durationMin":60},{"serviceId":"nails","name":"Nails","kind":"EXTRA","priceCents":6000,"durationMin":10}]}],"subtotalCents":44000,"cardFeeCents":1000,"cardTotalCents":45000,"cashTotalCents":44000,"acceptsCash":true,"summary":"R440 cash, or R450 by card. About 70 minutes."}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/availability":{"post":{"operationId":"findTimes","tags":["Booking"],"summary":"Open times","description":"Open start times over a date range (at most 31 days; default the next 7), from the same engine as the app. Same inputs as the quote.","x-mcp-tool":{"name":"find_times","title":"Find open times","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"Finds open start times for a visit, day by day, with the price. Same inputs as get_quote, plus optional `from`/`to` dates (YYYY-MM-DD, local; default today and the next 6 days, at most 31 days) and a `windowStart`/`windowEnd` time of day (HH:MM, e.g. 08:00–12:00 for \"morning\").\nOvernights and several days: when the answer's `mode` is STAY (an overnight service), ask the start date, the number of nights and the evening and morning windows (`windows`) and call again with `stay`; for a service with `multiDay` true the person may want visits over several days: call again with `visits` (start date, days, visits a day, a window each). The answer's `plan` says whether it all fits and `quote` is the total. Book with the same `stay` or `visits` (no start or resourceId).\nEach slot has `start` (ISO instant) and `resourceId`: pass both unchanged to book. Offer the person a few times that fit what they asked; don't invent times. `NO_AVAILABILITY` means nothing is open in the range: `reason` says why (outside hours, a closed day, fully booked), `message` says it in words to pass on, and `alternatives` are the next open times to offer; only when there are none in 14 days is the request kept (`leadId`) for a person at NogPets. An address we don't serve (another town or country) is a 409 `NO_COVERAGE` with the same `leadId`, `message` and `next`.\n"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimesRequest"},"example":{"category":"grooming","postalCode":"7613","pets":[{"name":"Biscuit","type":"DOG","weightKg":8,"coat":"SHORT","serviceIds":["full-groom"]}],"from":"2026-09-29","to":"2026-09-29","windowStart":"08:00","windowEnd":"12:00"}}}},"responses":{"200":{"description":"Days and their open slots","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Times"},"example":{"durationMin":60,"quote":{"category":"grooming","durationMin":60,"pets":[{"name":"Biscuit","items":[{"serviceId":"full-groom","name":"Full groom","kind":"PRIMARY","priceCents":38000,"durationMin":60}]}],"subtotalCents":38000,"cardFeeCents":1000,"cardTotalCents":39000,"cashTotalCents":38000,"acceptsCash":true,"summary":"R380 cash, or R390 by card. About 60 minutes."},"days":[{"date":"2026-09-29","label":"Tue 29 Sep","slots":[{"start":"2026-09-29T06:00:00.000Z","time":"08:00","resourceId":"van-1"},{"start":"2026-09-29T06:30:00.000Z","time":"08:30","resourceId":"van-1"}]}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/me":{"get":{"operationId":"myProfile","tags":["Account"],"summary":"Who am I","security":[{"oauth2":["profile"]},{"apiKey":[]}],"x-scopes":["profile"],"x-mcp-tool":{"name":"my_profile","title":"The person's profile","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"The signed-in person's name, email and phone, how many pets and addresses they have saved, and what this connection may do (scopes).\nUse it to greet them or to check who you're booking for.\n"},"responses":{"200":{"description":"The profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"},"example":{"uid":"u-client","name":"Sam Test","email":"client@nogpets.test","phone":"+27820000001","pets":2,"addresses":2,"client":{"id":"c_1","name":"Claude"},"scopes":["profile","pets","addresses","bookings:read","bookings:write"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/v1/pets":{"get":{"operationId":"listPets","tags":["Account"],"summary":"The person's pets","security":[{"oauth2":["pets"]},{"apiKey":[]}],"x-scopes":["pets"],"x-mcp-tool":{"name":"list_pets","title":"The person's pets","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"The person's saved pets: id, name, type, breed, weight and coat. Use a pet's `id` as `petId` in get_quote, find_times and book.\nIf the pet they mean isn't there, ask for its type, weight and coat and add it with add_pet.\n"},"responses":{"200":{"description":"Pets","content":{"application/json":{"schema":{"type":"object","required":["pets"],"properties":{"pets":{"type":"array","items":{"$ref":"#/components/schemas/Pet"}}}},"example":{"pets":[{"id":"biscuit","name":"Biscuit","type":"DOG","breed":"Boston terrier","weightKg":8,"coat":"SHORT","birthYear":2021,"notes":"Pulls on the lead."}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"addPet","tags":["Account"],"summary":"Add a pet","security":[{"oauth2":["pets"]},{"apiKey":[]}],"x-scopes":["pets"],"x-mcp-tool":{"name":"add_pet","title":"Add a pet","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"description":"Saves a new pet on the person's account. Needs `name`, `type` (DOG or CAT), `weightKg` (a number; an estimate is fine) and `coat` (SHORT, MEDIUM or LONG); `breed`, `birthYear` and `notes` are optional.\nAsk the person for what you don't know; don't guess the weight or coat. Returns the pet with its `id` for booking.\n"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewPet"},"example":{"name":"Rex","type":"DOG","weightKg":30,"coat":"LONG","breed":"Golden retriever"}}}},"responses":{"201":{"description":"The saved pet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Pet"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/v1/addresses":{"get":{"operationId":"listAddresses","tags":["Account"],"summary":"The person's addresses","security":[{"oauth2":["addresses"]},{"apiKey":[]}],"x-scopes":["addresses"],"x-mcp-tool":{"name":"list_addresses","title":"The person's addresses","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"The person's saved addresses (label such as Home, street, suburb, notes like a gate code). Use an address's `id` as `addressId` in get_quote, find_times and book.\nIf they want a visit somewhere new, save it with add_address.\n"},"responses":{"200":{"description":"Addresses","content":{"application/json":{"schema":{"type":"object","required":["addresses"],"properties":{"addresses":{"type":"array","items":{"$ref":"#/components/schemas/Address"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"addAddress","tags":["Account"],"summary":"Add an address","security":[{"oauth2":["addresses"]},{"apiKey":[]}],"x-scopes":["addresses"],"x-mcp-tool":{"name":"add_address","title":"Add an address","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"description":"Saves an address on the person's account. Needs `label` (e.g. Home) and `line1` (house number and street), and the suburb or postal code (in `suburb`/`postalCode`, or inside `line1`; abroad, `city` and the country in `line1` or `city`); `lat`/`lng` if you have the exact point; `notes` for a gate code or where to park.\nReturns the address with its `id` and which service lines cover it. `UNKNOWN_PLACE` means the suburb or postal code wasn't recognised: ask the person for it.\n"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewAddress"},"example":{"label":"Home","line1":"14 Kromrivier Street","suburb":"Die Boord","postalCode":"7613","notes":"Gate code 1234"}}}},"responses":{"201":{"description":"The saved address and its coverage","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Address"},{"type":"object","required":["covered","lines"],"properties":{"covered":{"type":"boolean"},"lines":{"type":"array","items":{"$ref":"#/components/schemas/LineCoverage"}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"}}}},"/v1/bookings":{"get":{"operationId":"listBookings","tags":["Booking"],"summary":"The person's upcoming bookings","security":[{"oauth2":["bookings:read"]},{"apiKey":[]}],"x-scopes":["bookings:read"],"x-mcp-tool":{"name":"list_bookings","title":"The person's bookings","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"The person's upcoming bookings (pending or accepted), soonest first: what, when, where, status, payment status and total.\nUse it when they ask what's booked, or to find the booking they want to move, cancel or pay (its `id`). `canPay: true` means a card booking still waiting for payment: get a link with pay_booking.\n"},"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"responses":{"200":{"description":"Bookings","content":{"application/json":{"schema":{"type":"object","required":["bookings"],"properties":{"bookings":{"type":"array","items":{"$ref":"#/components/schemas/Booking"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"book","tags":["Booking"],"summary":"Book a visit","description":"Books a slot from `find_times`. The server reprices and rechecks the slot. CARD →\nPENDING with a `payUrl` for the person to open (Payfast). CASH → needs `confirm: true`\n(else 409 `CONFIRM_REQUIRED` with the summary) and is PENDING with CASH_DUE.\n","security":[{"oauth2":["bookings:write"]},{"apiKey":[]}],"x-scopes":["bookings:write"],"x-mcp-tool":{"name":"book","title":"Book a visit","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"description":"Books a visit for the person. Needs `category`, a saved `addressId` (list_addresses/add_address), `pets` as [{petId, serviceIds}] with saved pet ids (list_pets/add_pet), the `start` and `resourceId` of a slot from find_times (unchanged), and `paymentMethod` CARD or CASH. Optional `notes` for the crew, and for walks `repeat` {freq: WEEKLY, days: [\"tue\"]}.\nBefore calling, show the person the service, pets, address, time and total, and get a clear yes.\nCARD: the booking is made and held, and the result has `payUrl`. Give the person that link to open and pay on Payfast themselves; you can't pay for them. It's confirmed once paid.\nCASH: send `confirm: true` only after the person said yes to the summary; without it you get CONFIRM_REQUIRED and the summary to show them. Cash is paid to the crew on the day.\nSLOT_TAKEN means someone got there first: call find_times again.\n"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookRequest"},"example":{"category":"grooming","addressId":"home","pets":[{"petId":"biscuit","serviceIds":["full-groom","nails"]}],"start":"2026-09-29T07:00:00.000Z","resourceId":"van-1","paymentMethod":"CARD"}}}},"responses":{"201":{"description":"Booked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookResult"},"example":{"bookingId":"bk_123","bookingIds":["bk_123"],"status":"PENDING","paymentMethod":"CARD","paymentStatus":"PENDING","totalCents":45000,"total":"R450","start":"2026-09-29T07:00:00.000Z","when":"Tue 29 Sep at 09:00","skipped":[],"payUrl":"https://api.nogpets.com/pay/b/bk_123?t=abc.def","next":"Open the payment link to pay R450 on Payfast. The time is held; it's confirmed once paid."}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bookings/{bookingId}":{"get":{"operationId":"getBooking","tags":["Booking"],"summary":"One booking","security":[{"oauth2":["bookings:read"]},{"apiKey":[]}],"x-scopes":["bookings:read"],"x-mcp-tool":{"name":"get_booking","title":"One booking","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"One of the person's bookings by id, with its status and payment status. Use it to check whether a booking was paid or accepted."},"parameters":[{"$ref":"#/components/parameters/BookingId"}],"responses":{"200":{"description":"The booking","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Booking"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/bookings/{bookingId}/times":{"post":{"operationId":"rescheduleTimes","tags":["Booking"],"summary":"Open times to move a booking to","security":[{"oauth2":["bookings:read"]},{"apiKey":[]}],"x-scopes":["bookings:read"],"x-mcp-tool":{"name":"find_reschedule_times","title":"Find times to move a booking","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"Open times a booking can move to (its own current slot doesn't block it), over `from`–`to` (YYYY-MM-DD, default the next 7 days). Pass a slot's `start` and `resourceId` to reschedule_booking.\nTOO_LATE means it's less than 12 hours away: the person must call NogPets.\n"},"parameters":[{"$ref":"#/components/parameters/BookingId"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"from":{"$ref":"#/components/schemas/Date"},"to":{"$ref":"#/components/schemas/Date"}}}}}},"responses":{"200":{"description":"Days and their open slots","content":{"application/json":{"schema":{"type":"object","required":["bookingId","durationMin","days"],"properties":{"bookingId":{"type":"string"},"durationMin":{"type":"integer"},"days":{"type":"array","items":{"$ref":"#/components/schemas/Day"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/bookings/{bookingId}/reschedule":{"post":{"operationId":"rescheduleBooking","tags":["Booking"],"summary":"Move a booking","description":"Same price and payment, until 12 hours before. The booking goes back to PENDING for the business to accept the new time.","security":[{"oauth2":["bookings:write"]},{"apiKey":[]}],"x-scopes":["bookings:write"],"x-mcp-tool":{"name":"reschedule_booking","title":"Move a booking","annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"description":"Moves one of the person's bookings to another open time from find_reschedule_times (`start` and `resourceId` unchanged). Same price, same payment. Allowed until 12 hours before (else TOO_LATE: they must call NogPets). Confirm the new time with the person first.\nThe booking goes back to PENDING until NogPets accepts the new time.\n"},"parameters":[{"$ref":"#/components/parameters/BookingId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["start"],"properties":{"start":{"type":"string","format":"date-time","description":"A slot's start from find_reschedule_times."},"resourceId":{"type":"string","maxLength":128}}}}}},"responses":{"200":{"description":"Moved","content":{"application/json":{"schema":{"type":"object","required":["bookingId","start","when","status","paymentStatus"],"properties":{"bookingId":{"type":"string"},"start":{"type":"string","format":"date-time"},"when":{"type":"string"},"resourceId":{"type":"string"},"status":{"$ref":"#/components/schemas/BookingStatus"},"paymentStatus":{"$ref":"#/components/schemas/PaymentStatus"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/bookings/{bookingId}/cancel":{"post":{"operationId":"cancelBooking","tags":["Booking"],"summary":"Cancel a booking","description":"Before it starts. A paid booking goes to REFUND_REQUESTED and NogPets refunds it. Needs `confirm: true`.","security":[{"oauth2":["bookings:write"]},{"apiKey":[]}],"x-scopes":["bookings:write"],"x-mcp-tool":{"name":"cancel_booking","title":"Cancel a booking","annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"description":"Cancels one of the person's bookings before it starts. A paid booking is refunded by NogPets (REFUND_REQUESTED; 5–7 working days). `series: true` also cancels the later weeks of a repeating walk.\nAsk the person to confirm which booking first, then send `confirm: true`.\n"},"parameters":[{"$ref":"#/components/parameters/BookingId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["confirm"],"properties":{"confirm":{"type":"boolean","description":"true once the person said yes to cancelling; anything else is CONFIRM_REQUIRED."},"series":{"type":"boolean","default":false,"description":"Also cancel the later weeks of a repeat."}}}}}},"responses":{"200":{"description":"Cancelled","content":{"application/json":{"schema":{"type":"object","required":["cancelled"],"properties":{"cancelled":{"type":"array","items":{"type":"string"},"description":"The booking ids cancelled."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/bookings/{bookingId}/pay":{"post":{"operationId":"payBooking","tags":["Booking"],"summary":"A payment link","description":"A fresh Payfast link (48 hours) for an unpaid card booking, for the person to open. No card data passes through here.","security":[{"oauth2":["bookings:write"]},{"apiKey":[]}],"x-scopes":["bookings:write"],"x-mcp-tool":{"name":"pay_booking","title":"Get a payment link","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"Returns a payment link for one of the person's unpaid card bookings. Give the person the `payUrl` to open: they pay on Payfast (card, Instant EFT, SnapScan) themselves. You can't pay for them.\nNOTHING_TO_PAY means it's paid or cash.\n"},"parameters":[{"$ref":"#/components/parameters/BookingId"}],"responses":{"200":{"description":"The link","content":{"application/json":{"schema":{"type":"object","required":["bookingId","totalCents","total","payUrl","expiresAt"],"properties":{"bookingId":{"type":"string"},"totalCents":{"type":"integer"},"total":{"type":"string"},"payUrl":{"type":"string","format":"uri"},"expiresAt":{"type":"string","format":"date-time"},"next":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/products":{"get":{"operationId":"browseShop","tags":["Shop"],"summary":"Shop products","description":"Active products with variants and stock, and the delivery options. `SHOP_OFF` (409) while the shop is closed.","x-shop":true,"x-mcp-tool":{"name":"browse_shop","title":"Browse the shop","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"Lists what NogPets sells (food, toys, beds, accessories, care) with prices, sizes (variants) and stock, plus the delivery options and fees. Filter with `category`, `petType` or a search `q`.\nUse a product's `id` (and a variant's `id` when it has variants) in quote_order and buy.\n"},"parameters":[{"name":"category","in":"query","schema":{"type":"string","enum":["FOOD","TOYS","BEDS","ACCESSORIES","CARE"]}},{"name":"petType","in":"query","schema":{"type":"string","enum":["DOG","CAT"]}},{"name":"q","in":"query","description":"Words to look for in the name, blurb and tags.","schema":{"type":"string","maxLength":100}}],"responses":{"200":{"description":"Products and delivery options","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Catalogue"}}}},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/orders/quote":{"post":{"operationId":"quoteOrder","tags":["Shop"],"summary":"Price a shop order","description":"The server's prices, delivery, discount and total. Never fails on stock or a bad code; it reports them in `problems`, `discountError`, `shippingError`.","x-shop":true,"x-mcp-tool":{"name":"quote_order","title":"Price a shop order","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"Prices a shop order before buying: lines, delivery fee, discount, total, and any problems (out of stock, bad code, delivery not possible to that postal code). Needs `items` [{productId, variantId?, qty}] and `shippingMethod` (from browse_shop; `visit` rides along with the person's next booking and needs `bookingId` and a token), plus `postalCode` for local delivery.\nShow the person the total before buy.\n"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderQuoteRequest"},"example":{"items":[{"productId":"kibble-lamb","variantId":"2kg","qty":1}],"shippingMethod":"courier"}}}},"responses":{"200":{"description":"The quote","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderQuote"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/orders":{"post":{"operationId":"buy","tags":["Shop"],"summary":"Place a shop order","description":"Reprices, checks stock, and places the order. Card → PENDING_PAYMENT with a `payUrl`\n(the order's page with a Pay button). Cash (only add-ons to the person's own cash\nbooking, `visit`) needs `confirm: true`.\n","x-shop":true,"security":[{"oauth2":["orders:write"]},{"apiKey":[]}],"x-scopes":["orders:write"],"x-mcp-tool":{"name":"buy","title":"Buy from the shop","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"description":"Places a shop order for the person. Same inputs as quote_order, plus `shipTo` {line1, suburb?, city, province?, postalCode, notes?} unless `shippingMethod` is `visit`. Show the person the items and total from quote_order and get a yes first.\nCard (default): the result has `payUrl`, the order's page. Give it to the person to pay on Payfast; unpaid orders close after 24 hours.\nCash is only for add-ons to their own cash booking (`shippingMethod: visit`, `bookingId`) and needs `confirm: true`.\n"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderRequest"}}}},"responses":{"201":{"description":"The order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/directory":{"get":{"operationId":"findPetBusinesses","tags":["Directory"],"summary":"Pet businesses near Stellenbosch","description":"Published listings of groomers, pet stores, vets, boarding, daycare, walkers and trainers, from public sources. NogPets is listed like everyone else (`isNogPets`).","x-mcp-tool":{"name":"find_pet_businesses","title":"Find pet businesses","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true},"description":"Searches the NogPets directory of pet businesses in and around Stellenbosch (Somerset West, Strand, Paarl, Franschhoek, Kuils River): groomers (salon and mobile), pet stores, vets, boarding, daycare, walkers, trainers. Filter by `town`, `category` or words in `q`.\nFacts only (name, area, phone, website, hours, services, prices only where the business publishes them). Use it when the person wants other options or something NogPets doesn't do, such as a vet.\nBusinesses on NogPets come first (`partner: true`): present them first, say they're on NogPets, and follow `bookWith`.\n"},"parameters":[{"name":"town","in":"query","description":"A town slug, e.g. stellenbosch, somerset-west, strand, paarl, franschhoek, kuils-river.","schema":{"type":"string","pattern":"^[a-z0-9-]{2,40}$"}},{"name":"category","in":"query","schema":{"$ref":"#/components/schemas/DirectoryCategory"}},{"name":"q","in":"query","schema":{"type":"string","maxLength":100}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"responses":{"200":{"description":"Listings","content":{"application/json":{"schema":{"type":"object","required":["listings"],"properties":{"listings":{"type":"array","items":{"$ref":"#/components/schemas/Listing"}},"next":{"type":"string"}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/signup-drafts":{"post":{"operationId":"prepareBusinessSignup","tags":["Business"],"summary":"Start a pet business's sign-up without an account","description":"No sign-in needed. Keeps what a chat already knows about a pet business (name, owner, contact, town, what they offer, prices as said) as a draft for 30 days and answers with `continueUrl`, a page on nogpets.com that fills in from it, asks what's missing (prices, area, hours) and sends the application to NogPets for review. The application belongs to the NogPets account with the owner's email (made if there isn't one); nothing is public until NogPets approves it. Needs `consent: true` after the person agreed to `consentText`. Limited per caller and per email.\n","x-public":true,"x-mcp-tool":{"name":"prepare_business_signup","title":"Sign up a pet business (no login)","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"description":"For a pet grooming, dog walking or pet sitting BUSINESS owner who wants to join NogPets (from any country), when they're not signed in to NogPets here: no account needed. Saves what you know and gives them a link that finishes the sign-up in about 2 minutes (prices, area, hours) and sends it to NogPets for review.\nAsk at most 3 short questions, only for what you don't know yet: the business name and town; their name and email (or phone); what they offer (grooming, walking, sitting). Pass prices only as the person said them (\"full groom R400\"), never invented. Before calling, tell them: \"NogPets keeps these details to set up your business application and to contact you about it, nothing else.\" and send `consent: true` once they're fine with it.\nThen give them `continueUrl` as a link with `message`. Don't ask for bank details, IDs or passwords. Never quote a fee (pricing for businesses: hello@nogpets.com); don't promise approval or a date.\nSigned in with the business:write permission? start_business_signup does every step in the chat instead.\n"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["businessName","town"],"properties":{"businessName":{"type":"string","maxLength":120,"description":"The business's name."},"contactName":{"type":"string","maxLength":120,"description":"The owner's name."},"email":{"type":"string","maxLength":254,"description":"The owner's email: their NogPets account uses it. Best way to reach them."},"phone":{"type":"string","maxLength":30,"description":"The owner's mobile (with the country code outside South Africa)."},"country":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"Two-letter country code (ZA, US, GB, AU…), if known. The phone's country code can say it."},"town":{"type":"string","maxLength":80,"description":"Where the business is based."},"categories":{"type":"array","maxItems":3,"items":{"type":"string","enum":["grooming","walking","sitting"]},"description":"What they offer."},"mode":{"type":"string","enum":["MOBILE","SALON","BOTH"],"description":"MOBILE: they go to the client; SALON: clients come to them."},"vans":{"type":"integer","minimum":0,"maximum":50},"staff":{"type":"integer","minimum":0,"maximum":500},"website":{"type":"string","maxLength":300},"about":{"type":"string","maxLength":300,"description":"One line about the business","in their words.":null},"services":{"type":"array","maxItems":30,"description":"Services and prices exactly as the person said them; the page turns them into a price list they check.","items":{"type":"object","additionalProperties":false,"required":["name"],"properties":{"name":{"type":"string","maxLength":80},"price":{"type":"string","maxLength":40,"description":"As said, e.g. \"R400\", \"$45\", \"from R350\"."},"category":{"type":"string","enum":["grooming","walking","sitting"]}}}},"note":{"type":"string","maxLength":500,"description":"Anything else they said that NogPets should know."},"consent":{"type":"boolean","description":"true once the person agreed that NogPets keeps these details to set up their application."}}},"example":{"businessName":"Happy Paws Mobile Grooming","contactName":"Anna Botha","email":"anna@happypaws.example","phone":"082 555 0101","town":"Somerset West","categories":["grooming"],"mode":"MOBILE","vans":1,"services":[{"name":"Full groom","price":"R420"},{"name":"Nail clip","price":"R80"}],"consent":true}}}},"responses":{"201":{"description":"The draft and the link that finishes it","content":{"application/json":{"schema":{"type":"object","properties":{"draftId":{"type":"string"},"continueUrl":{"type":"string","format":"uri","description":"The page that finishes the sign-up. Give it to the person as a link."},"expiresAt":{"type":"string","format":"date-time"},"summary":{"type":"string","description":"What was saved","to read back.":null},"message":{"type":"string","description":"What to tell the person","with the link.":null},"next":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/business/applications":{"get":{"operationId":"getSignupStatus","tags":["Business"],"summary":"A business sign-up's checklist and status","description":"The person's business application (the one named, else the newest) with its checklist, what's missing and the signed status page link; plus a list of all their applications.","security":[{"oauth2":["business:write"]},{"apiKey":[]}],"x-scopes":["business:write"],"x-scope-gated":true,"x-mcp-tool":{"name":"get_signup_status","title":"Business sign-up progress","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"Business sign-up and management, any step: shows the pet business's NogPets application (the one given by applicationId, else the newest) with its country, currency and time zone, its checklist (details, services, area, resources, payfast or payout, staff, listing), `readyToSubmit`, `next` (what to do now) and `statusUrl`, a page the person can open to see progress.\nUse it to pick up where a sign-up left off, or after submitting to see whether NogPets approved it (status DRAFT → SUBMITTED → APPROVED or REJECTED with `reviewNote`).\n"},"parameters":[{"name":"applicationId","in":"query","description":"The application; left out, the newest.","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$"}}],"responses":{"200":{"description":"The application (null when there is none) and the list","content":{"application/json":{"schema":{"type":"object","required":["application"],"properties":{"application":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/BusinessApplication"}]},"applications":{"type":"array","items":{"type":"object","properties":{"applicationId":{"type":"string"},"name":{"type":"string"},"status":{"$ref":"#/components/schemas/ApplicationStatus"}}}},"next":{"type":"string"},"welcomeUrl":{"type":"string","format":"uri"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"startBusinessSignup","tags":["Business"],"summary":"Start (or update) a pet business's sign-up","description":"Step 1 of registering a pet-care business on NogPets, from any country. Creates a DRAFT application owned by the signed-in person, or updates its details when `applicationId` is given. `country` (ISO 3166) is required for a new one unless the phone's country code says it; `currency` (ISO 4217) and `timezone` (IANA) default from the country when it has one of each. Nothing is public until NogPets approves it.\nThe order: startBusinessSignup → addBusinessServices → setServiceArea → addResources → setOperatingHours → inviteStaff (optional) → connectPayfast (optional, South Africa only) → getSignupStatus → submitBusinessForReview.\n","security":[{"oauth2":["business:write"]},{"apiKey":[]}],"x-scopes":["business:write"],"x-scope-gated":true,"x-mcp-tool":{"name":"start_business_signup","title":"Register a pet business (step 1)","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"description":"Register a pet grooming, dog walking or pet sitting BUSINESS on NogPets, from anywhere in the world (not for booking a groom). Step 1 of 9: creates the business's application with its details; call again with `applicationId` to change them.\nWhat they get once NogPets approves: a NogPets business account with a staff app (Today, calendar, services, vans and walkers, manual bookings), a listing in the NogPets directory, and clients booking them in the NogPets app, on WhatsApp and through assistants as NogPets opens in their area. Card payments through Payfast in South Africa; elsewhere NogPets arranges payouts after approval. Pricing for businesses isn't published: tell them \"talk to NogPets\" (hello@nogpets.com); never quote a fee.\nAsk the person for: business name (and trading name if different), their own name, phone (with the country code outside South Africa), email, website, the `country` it's in (two-letter code: ZA, US, GB, AU…), the town and suburbs they serve, what they offer (`categories`: grooming, walking, sitting), whether they're MOBILE (they go to the client), a SALON, or BOTH, and how many vans and staff. `currency` and `timezone` fill in from the country when it has one of each; if the checklist says they're missing (the US, Canada, Australia…), ask. Outside South Africa, optionally `payoutPreference` {method, note}: how they'd like to be paid, never bank details. Don't invent any of it.\nIf the answer has `possibleListings`, the business may already be in the NogPets directory: ask whether one is theirs and pass its id as `claimListingId`.\nThen: add_business_services → set_service_area → add_resources → set_operating_hours → invite_staff (optional) → connect_payfast (optional, South Africa only) → get_signup_status → submit_business_for_review. Give the person `statusUrl` so they can watch progress.\n"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessDetails"},"examples":{"southAfrica":{"value":{"businessName":"Happy Paws Grooming (Pty) Ltd","tradingName":"Happy Paws Mobile Grooming","contactName":"Anna Botha","phone":"082 555 0101","email":"anna@happypaws.example","website":"happypaws.example","country":"ZA","town":"Somerset West","suburbs":["Heldervue","Helderberg Estate"],"categories":["grooming"],"mode":"MOBILE","vans":1,"staff":2,"whatsappOptIn":true}},"abroad":{"value":{"businessName":"Lone Star Mobile Grooming LLC","contactName":"Jordan Reyes","phone":"+1 512 555 0100","email":"jordan@lonestargroom.example","country":"US","currency":"USD","timezone":"America/Chicago","town":"Austin, TX","categories":["grooming"],"mode":"MOBILE","vans":2,"payoutPreference":{"method":"BANK_TRANSFER","note":"ACH to our business account in USD"}}}}}}},"responses":{"200":{"description":"The updated application","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessApplication"}}}},"201":{"description":"The new application","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessApplication"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/applications/{applicationId}/services":{"parameters":[{"$ref":"#/components/parameters/ApplicationId"}],"post":{"operationId":"addBusinessServices","tags":["Business"],"summary":"Add services and prices to a sign-up","description":"Step 2. Adds or replaces the business's services (the NogPets service model: one PRIMARY per booking per pet plus EXTRAs, prices by weight and coat tiers, durations), or starts from NogPets' own menu with `useTemplate`.","security":[{"oauth2":["business:write"]},{"apiKey":[]}],"x-scopes":["business:write"],"x-scope-gated":true,"x-mcp-tool":{"name":"add_business_services","title":"Business sign-up: services and prices (step 2)","annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"description":"Business sign-up step 2: the services the business sells, with prices in the business's own currency in minor units (cents: R380 = 38000 in ZAR, $45 = 4500 in USD; whole units for currencies without cents, like JPY) and durations in minutes. Each line they offer needs at least one PRIMARY service (the main thing booked: a full groom, a 60-minute walk); EXTRAs are add-ons (nails, teeth, flea wash).\nPrices can depend on the pet: `tiers` [{petType?, coat?, minKg?, maxKg?, priceCents, durationMin}], first match wins, minKg inclusive, maxKg exclusive; `priceCents`/`durationMin` are the fallback. Walks can be group walks (`groupSize` > 1).\nFastest start: `useTemplate: true` copies NogPets' own menu for their lines, marked fromTemplate: in rand for a ZAR business (optionally `priceAdjustPct`, e.g. -10); in any other currency with no prices (`needsPrice`), so ask the person each price. Then send changes by service `id`. Sending a service with an existing `id` (or the same name) replaces it; `removeIds` deletes; `replace: true` starts over. Never make up prices: ask.\n"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessServicesRequest"},"example":{"services":[{"category":"grooming","kind":"PRIMARY","name":"Full groom","blurb":"Bath, cut, blow-dry, nails and ears.","petTypes":["DOG"],"priceCents":40000,"durationMin":60,"tiers":[{"maxKg":10,"priceCents":40000,"durationMin":60},{"minKg":10,"maxKg":25,"priceCents":52000,"durationMin":75},{"minKg":25,"priceCents":68000,"durationMin":90}]},{"category":"grooming","kind":"EXTRA","name":"Nail clip","priceCents":8000,"durationMin":10}]}}}},"responses":{"200":{"description":"The application","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessApplication"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/applications/{applicationId}/area":{"parameters":[{"$ref":"#/components/parameters/ApplicationId"}],"post":{"operationId":"setServiceArea","tags":["Business"],"summary":"Set where the business works","description":"Step 3. Sets the whole service area (each call replaces it) as proposed territories, PENDING until NogPets approves them.","security":[{"oauth2":["business:write"]},{"apiKey":[]}],"x-scopes":["business:write"],"x-scope-gated":true,"x-mcp-tool":{"name":"set_service_area","title":"Business sign-up: service area (step 3)","annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"description":"Business sign-up step 3: where the business works, anywhere in the world, sent whole each time (it replaces the last one). The simplest: `radiusKm` (how far they travel, e.g. 15) around `centerAddress` (a town or street in the business's country, e.g. \"Somerset West\" or \"Austin, TX\") or `center` {lat, lng}, with an optional `centerName`. Or `suburbs` as [{name, postalCode}] (the postal code or ZIP makes the area bookable; a suburb NogPets already knows borrows its shape), and/or `postalCodes`.\nThe answer lists the proposed areas (PENDING until NogPets approves) and `overlaps` with areas other businesses already serve: that's fine, NogPets decides who books where. A checklist item that says \"Needs a postal code\" means ask the person for it.\n"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAreaRequest"},"example":{"suburbs":[{"name":"Heldervue","postalCode":"7130"},{"name":"Helderberg Estate","postalCode":"7130"}],"center":{"lat":-34.0766,"lng":18.8433},"radiusKm":8,"centerName":"Somerset West"}}}},"responses":{"200":{"description":"The application","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessApplication"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/applications/{applicationId}/resources":{"parameters":[{"$ref":"#/components/parameters/ApplicationId"}],"post":{"operationId":"addResources","tags":["Business"],"summary":"Add vans, walkers and sitters with working hours","description":"Step 4. The things clients book a time on (a grooming van, a walker, a sitter), each with its working week.","security":[{"oauth2":["business:write"]},{"apiKey":[]}],"x-scopes":["business:write"],"x-scope-gated":true,"x-mcp-tool":{"name":"add_resources","title":"Business sign-up: vans, walkers, sitters (step 4)","annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"description":"Business sign-up step 4: what clients book time on. `kind` VAN does grooming (a salon's grooming table is a VAN too for now), WALKER does walks, SITTER does sitting. Each needs a `name` (\"Van 1\", \"Thandi\") and a `week`: {mon: [{start: \"08:00\", end: \"16:00\"}], …} in local time; leave out days off. A resource sent without `week` takes the business's hours from set_operating_hours (call that first, or after to set every resource at once). Optional: `slotStepMin` (30), `travelBufferMin` (15 for vans).\nEvery line the business offers needs at least one. Same `id` or name replaces; `removeIds` deletes; `replace: true` starts over. Ask for the real hours; don't assume.\n"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourcesRequest"},"example":{"resources":[{"kind":"VAN","name":"Van 1","week":{"mon":[{"start":"08:00","end":"16:00"}],"tue":[{"start":"08:00","end":"16:00"}],"wed":[{"start":"08:00","end":"16:00"}],"thu":[{"start":"08:00","end":"16:00"}],"fri":[{"start":"08:00","end":"14:00"}]}}]}}}},"responses":{"200":{"description":"The application","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessApplication"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/applications/{applicationId}/hours":{"parameters":[{"$ref":"#/components/parameters/ApplicationId"}],"post":{"operationId":"setOperatingHours","tags":["Business"],"summary":"Set the business's operating hours","description":"Step 5. One working week for the whole business (every van, walker and sitter, and any added later without their own), or for the resources named in `resourceIds`.","security":[{"oauth2":["business:write"]},{"apiKey":[]}],"x-scopes":["business:write"],"x-scope-gated":true,"x-mcp-tool":{"name":"set_operating_hours","title":"Business sign-up: operating hours","annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"description":"Business sign-up step 5: when the business works, as a week in the business's own local time (its `timezone`, e.g. America/Chicago): {mon: [{start: \"08:00\", end: \"17:00\"}], …, sat: [{start: \"08:00\", end: \"13:00\"}]}; leave out days off; up to 6 ranges a day for a lunch break or split shifts.\nWithout `resourceIds` it sets the business's hours and every van, walker and sitter's week, and resources added later without a week get them too. With `resourceIds` (ids from add_resources) only those change, e.g. a van that also works Saturdays. It replaces the hours it sets. Ask for the real hours; don't assume.\n"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HoursRequest"},"example":{"week":{"mon":[{"start":"08:00","end":"17:00"}],"tue":[{"start":"08:00","end":"17:00"}],"wed":[{"start":"08:00","end":"17:00"}],"thu":[{"start":"08:00","end":"17:00"}],"fri":[{"start":"08:00","end":"17:00"}],"sat":[{"start":"08:00","end":"13:00"}]}}}}},"responses":{"200":{"description":"The application","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessApplication"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/applications/{applicationId}/staff":{"parameters":[{"$ref":"#/components/parameters/ApplicationId"}],"post":{"operationId":"inviteStaff","tags":["Business"],"summary":"Invite staff","description":"Step 6 (optional). Staff (groomers, walkers, managers) to invite once the business is approved, by email or phone, as manager or crew, with the resources they work.","security":[{"oauth2":["business:write"]},{"apiKey":[]}],"x-scopes":["business:write"],"x-scope-gated":true,"x-mcp-tool":{"name":"invite_staff","title":"Business sign-up: staff and groomers (optional)","annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"description":"Business sign-up step 6, optional: the people who work for the business (groomers, walkers, sitters, managers), by `email` and/or `phone`, each with a `role`: `manager` (services, resources, manual bookings) or `crew` (sees and works the bookings), a `jobTitle` (\"Groomer\") and the `resourceIds` they work (the van a groomer is on, ids from add_resources). The owner is already in; don't add them.\nInvites go out when NogPets approves the business: people who already have a NogPets account join straight away, the rest when they sign up with that email or number. The same email or phone replaces; `replace: true` starts over.\n"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteRequest"},"example":{"invites":[{"name":"Thandi","phone":"071 555 0199","role":"crew","jobTitle":"Groomer","resourceIds":["van-1"]},{"name":"Pieter","email":"pieter@example.com","role":"manager"}]}}}},"responses":{"200":{"description":"The application","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessApplication"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/applications/{applicationId}/payfast":{"parameters":[{"$ref":"#/components/parameters/ApplicationId"}],"post":{"operationId":"connectPayfast","tags":["Business"],"summary":"Connect a Payfast merchant (id only)","description":"Step 7 (optional; South African businesses only, needed for card payments). Stores the business's Payfast merchant id for split payments, pending NogPets' verification. Never send a merchant key or passphrase; the schema refuses any field but the id. Elsewhere 409 `PAYFAST_ZA_ONLY`.","security":[{"oauth2":["business:write"]},{"apiKey":[]}],"x-scopes":["business:write"],"x-scope-gated":true,"x-mcp-tool":{"name":"connect_payfast","title":"Business sign-up: Payfast (card payments)","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"Business sign-up step 7, SOUTH AFRICAN businesses only, optional but needed for card payments: the business's Payfast merchant id (digits only, on the Payfast dashboard under Settings). ONLY the merchant id: never ask for, accept or repeat the merchant key or passphrase; if the person pastes one, tell them to keep it private.\nHow money flows: the client pays through NogPets' Payfast checkout and Payfast splits the payment, sending the business its share to its own merchant account. No Payfast account yet? They sign up at payfast.io (business account, bank details, ID); skip this step and add it later. Without it, clients pay cash.\nA business outside South Africa skips this step (it answers 409 `PAYFAST_ZA_ONLY`): save how they'd like to be paid as `payoutPreference` with start_business_signup instead (a method and a short note, never account numbers).\n"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayfastRequest"},"example":{"merchantId":"10012345"}}}},"responses":{"200":{"description":"The application, with `payfastInfo` to explain to the person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessApplication"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/applications/{applicationId}/submit":{"parameters":[{"$ref":"#/components/parameters/ApplicationId"}],"post":{"operationId":"submitBusinessForReview","tags":["Business"],"summary":"Submit a sign-up for NogPets' review","description":"The last step. Without `confirm` it answers 409 `CONFIRM_REQUIRED` with `details.summary` to show the person; with `confirm: true` the application goes to NogPets (SUBMITTED) and can't change until they answer. `NOT_READY` lists what's missing.","security":[{"oauth2":["business:write"]},{"apiKey":[]}],"x-scopes":["business:write"],"x-scope-gated":true,"x-mcp-tool":{"name":"submit_business_for_review","title":"Business sign-up: submit for review (last step)","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"description":"Business sign-up, last step: sends the application to NogPets. First call it without `confirm`: the answer is CONFIRM_REQUIRED with a summary; show it to the person, and only once they say it's right, call again with `confirm: true`.\nAfter that it's locked while NogPets reviews it (usually within two working days). The owner gets an email (and a WhatsApp message if they opted in) when it's approved or when changes are needed; get_signup_status and `statusUrl` show where it stands. On approval they sign in to the NogPets app with the same account to manage bookings.\n"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitRequest"},"example":{"confirm":true}}}},"responses":{"200":{"description":"Submitted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessApplication"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/overview":{"get":{"operationId":"businessOverview","tags":["Run"],"summary":"Today, this week and what's next","description":"Today's and this week's bookings and their value, what's waiting to be accepted or paid, the next visit, the vans and walkers (paused or not), upcoming time off, service areas and price changes set for later. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"business_overview","title":"Business overview","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"Run your pet grooming business: start here when the owner asks \"how's my day/week\", \"what's next\" or anything about their business. Answers today's and this week's bookings and value (what the business earns, in its own currency), bookings waiting to be accepted or paid, the next visit, each van/walker/sitter (id, paused), upcoming time off (ids for remove_time_off), service areas and scheduled price changes.\nWorks for the owner or a manager; staff see only their own van or walker and no money. If it answers NOT_A_MEMBER, the person's business isn't approved on NogPets yet: use get_signup_status / start_business_signup. If it answers WHICH_BUSINESS, ask which business and pass bizId."},"parameters":[{"$ref":"#/components/parameters/BizId"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizOverview"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/bookings":{"get":{"operationId":"listBusinessBookings","tags":["Run"],"summary":"Bookings over a date range","description":"The business's bookings between two dates (default the next 7 days), by van or walker and status. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"list_business_bookings","title":"The business's bookings","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"The business's bookings over a date range (default the next 7 days), optionally for one van/walker (resourceId) or one status (PENDING = waiting for the business to accept, ACCEPTED, COMPLETED, CANCELLED, REJECTED; default: pending, accepted and done). Each has the client (with a clientId for get_client), pets and services, address, payment and whether it's unpaid. Dates are the business's local days. Use get_day_plan for one day's route, list_unpaid_bookings for who owes."},"parameters":[{"$ref":"#/components/parameters/BizId"},{"name":"from","in":"query","required":false,"description":"First day, YYYY-MM-DD, in the business's own time zone.","schema":{"$ref":"#/components/schemas/Date"}},{"name":"to","in":"query","required":false,"description":"Last day, inclusive.","schema":{"$ref":"#/components/schemas/Date"}},{"name":"period","in":"query","required":false,"description":"Instead of from/to.","schema":{"$ref":"#/components/schemas/Period"}},{"name":"resourceId","in":"query","required":false,"description":"One van, walker or sitter (business_overview lists them).","schema":{"$ref":"#/components/schemas/Id"}},{"name":"status","in":"query","required":false,"description":"Only this status.","schema":{"$ref":"#/components/schemas/BookingStatus"}},{"name":"limit","in":"query","required":false,"description":"At most this many (100).","schema":{"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizBookings"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}},"post":{"operationId":"createBookingForClient","tags":["Run"],"summary":"A phone or walk-in booking, made by the business","description":"The business books a client itself (a phone call, a walk-in, a message): an existing client (clientId, their pets by petKey and address by addressKey from get_client) or a new one (name, phone and consentNote), the services, a time and the van or walker. It's placed where the van or walker is free (working hours don't bind the business's own bookings), ACCEPTED, cash due on the day or a Payfast pay link for the client. Without confirm: 409 CONFIRM_REQUIRED with the summary. South African businesses only (else NOT_AVAILABLE_IN_COUNTRY). Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"create_booking_for_client","title":"Book a client in","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"description":"Book a client in for the business (\"Tina called, book Max for his usual groom next Tuesday\"). Steps: find_client (their clientId) → get_client (pets with petKey and usual serviceIds, addresses with addressKey) → find_business_times (category, clientId + pets, a date range) → this tool with start and resourceId from those times. A new client: client {name, phone} and consentNote (how they agreed to be booked and to their details being kept, in the person's words; ask), pets by value {name, type, weightKg, coat, serviceIds} and address {line1, suburb, postalCode}.\npaymentMethod CASH (paid on the day) or CARD (the answer has a payUrl: the client pays on Payfast themselves; send_payment_link can send it to them). Never take card details.\nFirst call without confirm: it answers CONFIRM_REQUIRED with details.summary (services, client, time, address, van, total). Read it to the person; only after a clear yes call again with confirm: true. For South African businesses only; elsewhere NOT_AVAILABLE_IN_COUNTRY: say bookings there are taken outside NogPets for now."},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizVisitRequest"}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizVisitResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/day-plan":{"get":{"operationId":"getDayPlan","tags":["Run"],"summary":"One day's visits in order, per van or walker","description":"For one day (default today, the business's time zone): each van, walker or sitter's hours, time off and visits in order with times, address, pets, services, notes, payment due, the gap before each visit and the straight-line distance from the last one. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"get_day_plan","title":"Day plan per van or walker","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"\"What's my day look like?\" / \"Where's Van 2 going tomorrow?\": each van, walker or sitter's day in order (date default today, YYYY-MM-DD, the business's local day; resourceId for one). Per visit: time, client and phone, address and its notes (gate codes), pets with weight, coat and services, booking notes, payment (and what's still due), the gap before it in minutes and the straight-line km from the stop before; tight = the gap is shorter than the travel time set. Also working hours and time off that day. Locations: each stop's mapUrl opens it on Google Maps, and each van or walker's directionsUrls is the day's driving route through the stops still to do, in order, from where the phone is (more than one link past 10 stops); give them as links. Distances are as the crow flies, not road routes: say so if you mention them. Staff see only their own van or walker."},"parameters":[{"$ref":"#/components/parameters/BizId"},{"name":"date","in":"query","required":false,"description":"The day (default today).","schema":{"$ref":"#/components/schemas/Date"}},{"name":"resourceId","in":"query","required":false,"description":"One van, walker or sitter (business_overview lists them).","schema":{"$ref":"#/components/schemas/Id"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DayPlan"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/next-booking":{"get":{"operationId":"nextBooking","tags":["Run"],"summary":"The visit happening now and the next one","description":"The visit under way (if any) and the next one, with pets, address notes and minutes until it starts. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"next_booking","title":"Next booking","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"\"Who's next?\" / \"Where am I going next?\": the visit happening now (if any) and the next one, with the client, address and gate notes (mapUrl: the address on Google Maps, to give as a link), pets and services and how many minutes until it starts. resourceId for one van or walker; staff get their own."},"parameters":[{"$ref":"#/components/parameters/BizId"},{"name":"resourceId","in":"query","required":false,"description":"One van, walker or sitter (business_overview lists them).","schema":{"$ref":"#/components/schemas/Id"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizNext"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/services":{"get":{"operationId":"listBusinessServices","tags":["Run"],"summary":"Services, prices by size and coat, packages","description":"The business's services per line with prices (and each tier's tierIndex for update_prices), durations, packages, and price changes set for later. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"list_business_services","title":"The business's services and prices","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"The business's own services and prices, per line (grooming, walking, sitting), in its currency. Services priced by size or coat have tiers, each with a tierIndex and a label (\"25 kg and up\", \"long coat\"): update_prices takes serviceId and tierIndex. Also the service ids that find_business_times and create_booking_for_client take in serviceIds, packages, and any price change already set for a later date."},"parameters":[{"$ref":"#/components/parameters/BizId"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizServices"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/times":{"post":{"operationId":"findBusinessTimes","tags":["Run"],"summary":"Open times across the business's vans and walkers","description":"Open times inside working hours for a visit of the business: from the pets and services (priced and timed by the business's own menu), a past booking to repeat, or a duration. South African businesses only (else NOT_AVAILABLE_IN_COUNTRY). Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"find_business_times","title":"Open times to book","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"Open times to book a client in, across the business's vans/walkers (or one resourceId), from the pets and services (clientId + pets with petKey, or pets by value with serviceIds), from a past booking to repeat (fromBookingId: same pets, services and length), or a plain durationMin; over from–to (default 7 days from today), optionally inside windowStart–windowEnd (HH:MM). Each slot has start (ISO) and resourceId to pass to create_booking_for_client or book_repeat, plus the local time. Only offer times from here."},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizTimesRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizTimes"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/clients":{"get":{"operationId":"findClient","tags":["Run"],"summary":"Search the business's own clients","description":"The business's own clients (anyone it has booked, or added) matching a name, a pet's name, a phone number or an email. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"find_client","title":"Find a client","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"Find one of the business's own clients by name (\"Tina\"), their pet's name (\"Max\"), phone (the last 6+ digits) or email. Only clients this business has booked or added: never other businesses' clients or NogPets' users at large. Answers clientId (for get_client, add_client_note, create_booking_for_client), phone, pets, last and next visit. Several matches: ask the person which."},"parameters":[{"$ref":"#/components/parameters/BizId"},{"name":"q","in":"query","required":true,"description":"A name, pet name, phone or email.","schema":{"type":"string","minLength":2,"maxLength":120}},{"name":"limit","in":"query","required":false,"description":"At most this many (10).","schema":{"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizClients"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/clients/{clientId}":{"parameters":[{"$ref":"#/components/parameters/ClientId"}],"get":{"operationId":"getClient","tags":["Run"],"summary":"A client: pets, addresses, notes, bookings","description":"One client of the business: contact, pets (petKey, usual services), addresses (addressKey), the business's notes, how they agreed to be booked, upcoming and past bookings. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"get_client","title":"Client details","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"One of the business's clients (clientId from find_client): phone and email, pets with petKey and their usual serviceIds, addresses with addressKey and notes, the business's own notes about them, upcoming bookings and the last 10. Use the petKey, serviceIds and addressKey to book them again (find_business_times, create_booking_for_client)."},"parameters":[{"$ref":"#/components/parameters/BizId"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizClient"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/clients/{clientId}/notes":{"parameters":[{"$ref":"#/components/parameters/ClientId"}],"post":{"operationId":"addClientNote","tags":["Run"],"summary":"A private note on a client","description":"Adds a note to one of the business's clients (only this business sees it). Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"add_client_note","title":"Add a note on a client","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"description":"Saves a note on one of the business's clients (\"Max bites when his ears are cleaned\", \"Gate code changed to 4411\"). Only this business sees it; get_client and get_day_plan show it. No card numbers, passwords or health data beyond what's needed for the pet's care."},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientNoteRequest"}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientNoteResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/earnings":{"get":{"operationId":"earningsSummary","tags":["Run"],"summary":"Gross, fees, net and by service over a period","description":"Earnings from visits in a period (default this week): gross, NogPets' card fee and Payfast's fee, net, received and still due, refunds, and by service, in the business's currency. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"earnings_summary","title":"Earnings","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"\"How much did I make this month?\": earnings from visits in a period (period this_week, last_week, this_month, last_month, today, next_7_days, or from/to), in the business's own currency. gross (what clients pay), fees (NogPets' card fee on card bookings and Payfast's own fee where reported), net, received so far, still due, refunds, and byService. Cancelled and rejected visits don't count. Report the numbers as given; never estimate or add fees of your own."},"parameters":[{"$ref":"#/components/parameters/BizId"},{"name":"period","in":"query","required":false,"description":"Instead of from/to.","schema":{"$ref":"#/components/schemas/Period"}},{"name":"from","in":"query","required":false,"description":"First day, YYYY-MM-DD, in the business's own time zone.","schema":{"$ref":"#/components/schemas/Date"}},{"name":"to","in":"query","required":false,"description":"Last day, inclusive.","schema":{"$ref":"#/components/schemas/Date"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizEarnings"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/payouts":{"get":{"operationId":"listPayouts","tags":["Run"],"summary":"How card money reaches the business","description":"Card payments for the business's bookings in a period (default this month), who they were paid to, and payouts for jobs NogPets passed to it. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"list_payouts","title":"Payouts and card payments","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"Card payments for the business's bookings in a period (default this month) with Payfast's fee and who received them (the business directly through a Payfast split, or NogPets, which then settles by hand), how settlement works for this business, and payouts for jobs NogPets passed to it. Say what the answer says; don't promise dates it doesn't give."},"parameters":[{"$ref":"#/components/parameters/BizId"},{"name":"period","in":"query","required":false,"description":"Instead of from/to.","schema":{"$ref":"#/components/schemas/Period"}},{"name":"from","in":"query","required":false,"description":"First day, YYYY-MM-DD, in the business's own time zone.","schema":{"$ref":"#/components/schemas/Date"}},{"name":"to","in":"query","required":false,"description":"Last day, inclusive.","schema":{"$ref":"#/components/schemas/Date"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizPayouts"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/unpaid":{"get":{"operationId":"listUnpaidBookings","tags":["Run"],"summary":"Who hasn't paid","description":"Bookings in a period (default this week) not paid yet: card bookings not paid or failed, and cash not marked received; and invoice links still open (openInvoices). Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"list_unpaid_bookings","title":"Unpaid bookings","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"\"Who hasn't paid this week?\": bookings in a period (default this week) with money outstanding: card bookings not paid (or the payment failed) and cash not yet marked received, with the client, amount and whether the visit is past (overdue); openInvoices lists invoice links (create_invoice_link) not paid yet. For a card booking, send_payment_link sends the client their Payfast link again. Never charge anyone."},"parameters":[{"$ref":"#/components/parameters/BizId"},{"name":"period","in":"query","required":false,"description":"Instead of from/to.","schema":{"$ref":"#/components/schemas/Period"}},{"name":"from","in":"query","required":false,"description":"First day, YYYY-MM-DD, in the business's own time zone.","schema":{"$ref":"#/components/schemas/Date"}},{"name":"to","in":"query","required":false,"description":"Last day, inclusive.","schema":{"$ref":"#/components/schemas/Date"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizUnpaid"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/prices":{"post":{"operationId":"updatePrices","tags":["Run"],"summary":"Change service prices, now or from a date","description":"Changes prices (and optionally durations) per service or per size/coat tier, by amount or percent, now or from effectiveFrom. Without confirm: 409 CONFIRM_REQUIRED with the summary and a before → after preview. Bookings already made keep their price. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"update_prices","title":"Change prices","annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false},"description":"\"Raise large-dog full grooms to R650 from next month\": list_business_services first (serviceId and the tier's tierIndex), then changes [{serviceId, tierIndex?, priceCents? | percent?, durationMin?}] in the business's currency's minor units (R650 = 65000). A service priced by size needs tierIndex for a fixed price (else AMBIGUOUS lists the tiers); percent (+10, -5) moves one tier or all. effectiveFrom YYYY-MM-DD (e.g. the 1st of next month) sets it for that day; left out, now.\nFirst call without confirm answers CONFIRM_REQUIRED with details.summary and details.preview (each price before → after): show it; after a clear yes, call again with confirm: true. Bookings already made keep their price. Never invent prices: use the person's numbers."},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceChangeRequest"},"example":{"changes":[{"serviceId":"full-groom","tierIndex":2,"priceCents":65000}],"effectiveFrom":"2026-10-01"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceChangeResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/hours":{"post":{"operationId":"setBusinessHours","tags":["Run"],"summary":"The weekly hours of the business or some vans and walkers","description":"Sets the working week (local time) for every van, walker and sitter, or those in resourceIds. Bookings outside the new hours stay booked and are listed. Needs confirm after the summary. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"set_business_hours","title":"Set working hours","annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"description":"The weekly working hours, in the business's local time: week {mon: [{start: \"08:00\", end: \"16:00\"}], …}, leaving out days off; for the whole business (every van/walker/sitter) or only resourceIds. It replaces the week it had. For one day or a few hours off use add_time_off instead.\nFirst call without confirm answers CONFIRM_REQUIRED with details.summary, including any bookings that would fall outside the new hours (they stay booked; nothing is cancelled): show it; after a yes, confirm: true."},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizHoursRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizHoursResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/time-off":{"post":{"operationId":"addTimeOff","tags":["Run"],"summary":"Days off or blocked hours","description":"Blocks a whole day, several days or some hours on one day, for one van, walker or sitter or the whole business: no new bookings then. Bookings already in that time are never cancelled; they're listed, and the block needs confirm when there are any. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"add_time_off","title":"Block time off","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"description":"\"Block Friday afternoon, the van's in for a service\": date (YYYY-MM-DD), and from–to (HH:MM, local) for part of a day, or toDate for several whole days; resourceId for one van/walker (business_overview lists them), left out = the whole business; reason (shown to staff). No new bookings in that time.\nIf bookings are already in that time it answers CONFIRM_REQUIRED listing them: they stay booked, nothing is cancelled. Tell the person, and after a yes send confirm: true; then offer to move (reschedule_business_booking) or cancel (cancel_business_booking) them one by one if they want. The answer's timeOffId undoes it (remove_time_off)."},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeOffRequest"},"example":{"date":"2026-10-02","from":"12:00","to":"17:00","resourceId":"van-1","reason":"Van service"}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeOffResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/time-off/{timeOffId}/remove":{"parameters":[{"$ref":"#/components/parameters/TimeOffId"}],"post":{"operationId":"removeTimeOff","tags":["Run"],"summary":"Opens blocked time again","description":"Removes one block of time off (timeOffId from business_overview or add_time_off). Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"remove_time_off","title":"Remove time off","annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"description":"Removes a block of time off so those times can be booked again. timeOffId from business_overview (upcoming time off) or add_time_off's answer."},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizOnly"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeOffRemoved"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/area":{"post":{"operationId":"updateServiceArea","tags":["Run"],"summary":"Add or drop service areas","description":"Adds areas (suburbs with postal codes, postal codes, or a radius around a place), which NogPets reviews before they take bookings, and/or drops areas (removeAreaIds, at once; bookings already made stay). Needs confirm after the summary. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"update_service_area","title":"Change where the business works","annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false},"description":"Where the business works. Add: suburbs [{name, postalCode}], postalCodes, or radiusKm around centerAddress (a town or street in the business's country) or center {lat, lng}. New ground is PENDING until NogPets reviews it (clients there can't book it yet). Drop: removeAreaIds (ids from business_overview's areas): no new bookings there from now; bookings already made stay. resourceIds limits added areas to some vans or walkers.\nFirst call without confirm answers CONFIRM_REQUIRED with details.summary: show it; after a yes, confirm: true."},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AreaChangeRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AreaChangeResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/resources/{resourceId}/pause":{"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"post":{"operationId":"pauseResource","tags":["Run"],"summary":"Stop new bookings for a van, walker or sitter","description":"A van, walker or sitter stops taking new bookings until resumed. Its bookings stay and are listed. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"pause_resource","title":"Pause a van or walker","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"Stops a van, walker or sitter taking new bookings (broken down, on leave, fully booked) until resume_resource. Its bookings stay booked and are listed in the answer: nothing is cancelled; ask the person what to do with them. For a single day or a few hours, add_time_off is better."},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PauseRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceState"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/resources/{resourceId}/resume":{"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"post":{"operationId":"resumeResource","tags":["Run"],"summary":"Take bookings again","description":"A paused van, walker or sitter takes bookings again. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"resume_resource","title":"Resume a van or walker","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"description":"A paused van, walker or sitter (pause_resource) takes new bookings again, in its working hours. Time off already set stays; business_overview shows which are paused."},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizOnly"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceState"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/bookings/{bookingId}/repeat":{"parameters":[{"$ref":"#/components/parameters/BookingId"}],"post":{"operationId":"bookRepeat","tags":["Run"],"summary":"Rebook a client's visit at a new time","description":"Books the same client, pets, services and address as a past booking at a new time, at today's prices. Without confirm: 409 CONFIRM_REQUIRED with the summary. South African businesses only. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"book_repeat","title":"Book the same again","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"description":"\"Book Max for his usual groom next Tuesday\": the same client, pets, services and address as one of their bookings (bookingId from get_client or list_business_bookings), at a new time, priced at today's prices. find_business_times with fromBookingId gives the open times; pass start (and resourceId; default the same van). paymentMethod defaults to what they paid last time.\nFirst call without confirm answers CONFIRM_REQUIRED with details.summary: read it to the person; after a yes, confirm: true."},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepeatRequest"}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizVisitResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/bookings/{bookingId}/payment-link":{"parameters":[{"$ref":"#/components/parameters/BookingId"}],"post":{"operationId":"sendPaymentLink","tags":["Run"],"summary":"The client's Payfast link, sent again","description":"For an unpaid card booking: the client's Payfast pay link (48 hours), sent to them on WhatsApp when they use NogPets on WhatsApp, and returned for the business to forward. Nothing is charged. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"send_payment_link","title":"Send a payment link","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"description":"For an unpaid card booking (list_unpaid_bookings): the client's Payfast link. NogPets sends it on WhatsApp when the client uses NogPets there (sent.whatsapp), and the answer has payUrl for the owner to forward. The client pays on Payfast themselves: this never charges anyone, and you never ask for card details. Cash bookings answer NOTHING_TO_PAY."},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizOnly"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizPayLink"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/invoices":{"post":{"operationId":"createInvoiceLink","tags":["Run"],"summary":"An invoice link with a QR code, to take a Payfast payment","description":"A Payfast payment link and a QR code for any amount the business wants paid (a walk-in, a nail clip at the door, something sold on the day), not tied to a booking. The client pays on Payfast themselves (card, Instant EFT, SnapScan, Zapper); NogPets' card fee is added on top as on a card booking. With a Payfast split the amount goes to the business's own Payfast account, else NogPets pays it over. South African businesses only (409 PAYFAST_ZA_ONLY). Without confirm: 409 CONFIRM_REQUIRED with the summary. Needs business:manage; owners and managers (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"create_invoice_link","title":"Create an invoice link with a QR code","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"description":"\"Give me an invoice link with a QR code for R350\": a Payfast payment link (payUrl) and a QR code image of it (qrUrl, a PNG to show the client or print) for an amount the business wants paid, e.g. a walk-in or something sold on the day. amountCents in the business's currency (R350 = 35000), description (what it's for), optionally clientName or clientId (find_client) and bookingId as a reference, expiresInDays (default 7, at most 30). NogPets' card fee is added on top for the client, as on card bookings; the answer says the total.\nFirst call without confirm answers CONFIRM_REQUIRED with details.summary: show it, and after a yes call again with confirm: true. The client pays on Payfast themselves: this never charges anyone, and you never ask for card details. Open links show in list_unpaid_bookings (openInvoices). Outside South Africa: PAYFAST_ZA_ONLY."},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceRequest"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceLink"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/bookings/{bookingId}/reschedule":{"parameters":[{"$ref":"#/components/parameters/BookingId"}],"post":{"operationId":"rescheduleBusinessBooking","tags":["Run"],"summary":"The business moves one of its bookings","description":"Moves a pending or accepted booking of the business to a new time (any time the van or walker is free), same price and payment; it becomes ACCEPTED and the client is told as the app tells them. Without confirm: 409 CONFIRM_REQUIRED. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"reschedule_business_booking","title":"Move a client's booking","annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false},"description":"Moves one of the business's bookings to another time (start from find_business_times, or a time the person gives; resourceId to change van or walker). Same price and payment. The client is told the new time the way NogPets tells them (push, email, WhatsApp); a client without a NogPets account must be told by the business.\nFirst call without confirm answers CONFIRM_REQUIRED with details.summary: after a yes, confirm: true. SLOT_TAKEN: pick another time."},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/business/bookings/{bookingId}/cancel":{"parameters":[{"$ref":"#/components/parameters/BookingId"}],"post":{"operationId":"cancelBusinessBooking","tags":["Run"],"summary":"The business cancels one of its bookings","description":"Cancels a pending or accepted booking (series: true for the rest of its repeats). A paid one goes to the refund list. The client is told as the app tells them. Without confirm: 409 CONFIRM_REQUIRED. Needs business:manage; the signed-in person must be an owner, manager or staff member of an approved NogPets business (bizId only if they run more than one).","security":[{"oauth2":["business:manage"]},{"apiKey":[]}],"x-scopes":["business:manage"],"x-scope-gated":true,"x-mcp-tool":{"name":"cancel_business_booking","title":"Cancel a client's booking","annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"description":"Cancels one of the business's bookings (series: true also cancels the rest of a repeating one); reason is kept for the record. A paid booking goes on NogPets' refund list and the money goes back through Payfast. The client is told the way NogPets tells them.\nFirst call without confirm answers CONFIRM_REQUIRED with details.summary (including any refund): read it to the person; only after a clear yes, confirm: true."},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizCancelRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BizCancelResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}}},"components":{"securitySchemes":{"oauth2":{"type":"oauth2","description":"OAuth 2.1, authorization code with PKCE (S256), public clients. Register with `POST /oauth/register` (RFC 7591). Access tokens last an hour; refresh tokens rotate.","flows":{"authorizationCode":{"authorizationUrl":"https://api.nogpets.com/oauth/authorize","tokenUrl":"https://api.nogpets.com/oauth/token","refreshUrl":"https://api.nogpets.com/oauth/token","scopes":{"profile":"See your name, email and phone","pets":"See and add your pets","addresses":"See and add your addresses","bookings:read":"See your bookings","bookings:write":"Book, move, cancel and get payment links for your bookings","orders:write":"Place shop orders for you to pay","business:write":"Set up and manage your pet business on NogPets","business:manage":"Run your pet business on NogPets"}}}},"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"npk_…","description":"A personal API key from the NogPets app (Profile → Connect an AI assistant). It carries the scopes chosen when it was made."}},"parameters":{"BizId":{"name":"bizId","in":"query","required":false,"description":"Only when the person runs more than one business.","schema":{"$ref":"#/components/schemas/Id"}},"ClientId":{"name":"clientId","in":"path","required":true,"description":"From find_client.","schema":{"$ref":"#/components/schemas/Id"}},"TimeOffId":{"name":"timeOffId","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Id"}},"ResourceId":{"name":"resourceId","in":"path","required":true,"description":"A van, walker or sitter (business_overview).","schema":{"$ref":"#/components/schemas/Id"}},"ApplicationId":{"name":"applicationId","in":"path","required":true,"description":"The application, from start_business_signup.","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$"}},"BookingId":{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$"}}},"responses":{"BadRequest":{"description":"The input is wrong (`INVALID_ARGUMENT`, or a pricing code such as `ONE_PRIMARY`, `PET_TYPE`, `UNKNOWN_SERVICE`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"ONE_PRIMARY","message":"Pick one main service for Biscuit"}}}}},"Unauthorized":{"description":"No token, or it's expired or revoked. The `WWW-Authenticate` header points at the resource metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"UNAUTHENTICATED","message":"A NogPets access token or API key is needed."}}}}},"Forbidden":{"description":"The token lacks a scope (`INSUFFICIENT_SCOPE`, with `details.scope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"INSUFFICIENT_SCOPE","message":"This needs the bookings:write scope.","details":{"scope":"bookings:write"}}}}}},"NotFound":{"description":"Not found, or not the person's.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"NOT_FOUND","message":"Booking not found"}}}}},"Conflict":{"description":"A rule said no: `NO_COVERAGE`, `NO_AVAILABILITY`, `SLOT_TAKEN`, `TOO_LATE`,\n`CONFIRM_REQUIRED` (with `details.summary`), `NOTHING_TO_PAY`, `SHOP_OFF`, `STOCK`,\n`SHIPPING`, `DISCOUNT`, `CASH`, `FAILED_PRECONDITION`; business sign-up: `UNDER_REVIEW`,\n`APPROVED`, `NOT_READY`, `TOO_MANY`, `LISTING_TAKEN`, `PAYFAST_ZA_ONLY`. `NO_COVERAGE`\ncarries `details.leadId`, `details.message` (tell the person) and `details.next`.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"slotTaken":{"value":{"error":{"code":"SLOT_TAKEN","message":"That time was just taken. Pick another."}}},"confirm":{"value":{"error":{"code":"CONFIRM_REQUIRED","message":"Show the person this summary and send confirm true once they say yes.","details":{"summary":"Full groom for Biscuit, Tue 29 Sep at 09:00, 14 Kromrivier Street. R440 cash on the day."}}}}}}}},"Unprocessable":{"description":"The place couldn't be recognised (`UNKNOWN_PLACE`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Too many requests (`RATE_LIMIT`). `Retry-After` says when to try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Id":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$"},"Period":{"type":"string","enum":["today","this_week","last_week","next_7_days","this_month","last_month"],"description":"A period in the business's own time zone; weeks run Monday to Sunday."},"Money":{"type":"object","properties":{"cents":{"type":"integer","description":"Minor units of the business's currency."},"text":{"type":"string","description":"Formatted, e.g. R650 or US$85."}}},"BizRef":{"type":"object","properties":{"bizId":{"type":"string"},"name":{"type":"string"},"role":{"type":"string","description":"owner, manager or crew (staff)."},"country":{"type":"string"},"countryName":{"type":"string"},"currency":{"type":"string"},"timezone":{"type":"string"},"canTakeBookings":{"type":"boolean","description":"False outside South Africa for now: bookings there aren't taken through NogPets."}}},"BizBooking":{"type":"object","properties":{"id":{"type":"string"},"when":{"type":"string","description":"Local day and time."},"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"},"status":{"$ref":"#/components/schemas/BookingStatus"},"category":{"type":"string"},"resourceId":{"type":"string"},"resource":{"type":"string"},"client":{"type":"object","properties":{"id":{"type":"string","description":"clientId for get_client."},"name":{"type":"string"},"phone":{"type":"string"}}},"what":{"type":"string","description":"Pets and services."},"address":{"type":"string"},"mapUrl":{"type":["string","null"],"description":"The address on Google Maps."},"notes":{"type":"string"},"paymentMethod":{"type":"string"},"paymentStatus":{"$ref":"#/components/schemas/PaymentStatus"},"total":{"type":"string"},"totalCents":{"type":"integer"},"unpaid":{"type":"boolean"},"source":{"type":"string"}}},"BizOverview":{"type":"object","required":["business"],"properties":{"business":{"$ref":"#/components/schemas/BizRef"},"today":{"type":"object","properties":{"date":{"type":"string"},"label":{"type":"string"},"bookings":{"type":"integer"},"value":{"$ref":"#/components/schemas/Money"}}},"thisWeek":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"bookings":{"type":"integer"},"value":{"$ref":"#/components/schemas/Money"},"waitingForYou":{"type":"integer","description":"Pending: waiting for the business to accept."},"unpaid":{"type":"integer"}}},"next":{"oneOf":[{"$ref":"#/components/schemas/BizBooking"},{"type":"null"}]},"resources":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string"},"categories":{"type":"array","items":{"type":"string"}},"paused":{"type":"boolean"},"pausedReason":{"type":"string"}}}},"timeOff":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"timeOffId"},"who":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"},"reason":{"type":"string"}}}},"areas":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","description":"APPROVED, or PENDING review by NogPets."}}}},"scheduledPriceChanges":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"from":{"type":"string"},"summary":{"type":"string"}}}},"money":{"type":"string"},"note":{"type":"string"}}},"BizBookings":{"type":"object","required":["bookings"],"properties":{"business":{"$ref":"#/components/schemas/BizRef"},"from":{"type":"string"},"to":{"type":"string"},"count":{"type":"integer"},"bookings":{"type":"array","items":{"$ref":"#/components/schemas/BizBooking"}}}},"Stop":{"type":"object","properties":{"bookingId":{"type":"string"},"time":{"type":"string","description":"09:00–10:15, local."},"start":{"type":"string"},"end":{"type":"string"},"status":{"type":"string"},"client":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"phone":{"type":"string"}}},"address":{"type":"string"},"addressNotes":{"type":"string"},"mapUrl":{"type":["string","null"],"description":"The stop on Google Maps (its stored point, else the address)."},"point":{"type":["object","null"],"description":"The stop's stored location, when there is one (for a map).","properties":{"lat":{"type":"number"},"lng":{"type":"number"}}},"pets":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"},"weightKg":{"type":"number"},"coat":{"type":"string"},"services":{"type":"array","items":{"type":"string"}}}}},"notes":{"type":"string"},"payment":{"type":"object","properties":{"method":{"type":"string"},"status":{"type":"string"},"due":{"type":"string"}}},"gapBeforeMin":{"type":["integer","null"]},"kmFromPrevious":{"type":["number","null"],"description":"Straight-line km from the stop before."},"tight":{"type":"boolean","description":"The gap is shorter than the travel time set."}}},"DayPlan":{"type":"object","required":["plan"],"properties":{"business":{"$ref":"#/components/schemas/BizRef"},"date":{"type":"string"},"label":{"type":"string"},"note":{"type":"string"},"plan":{"type":"array","items":{"type":"object","properties":{"resourceId":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string"},"paused":{"type":"boolean"},"hours":{"type":"array","items":{"type":"string"}},"timeOff":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"},"wholeBusiness":{"type":"boolean"},"reason":{"type":"string"}}}},"stops":{"type":"array","items":{"$ref":"#/components/schemas/Stop"}},"directionsUrls":{"type":"array","description":"Google Maps driving directions through the stops still to do, in order, starting where the phone is. At most 9 stops between start and end per link; a longer day has more than one, each starting at the last one's end.","items":{"type":"string"}},"summary":{"type":"string"}}}}}},"BizNext":{"type":"object","properties":{"business":{"$ref":"#/components/schemas/BizRef"},"now":{"oneOf":[{"$ref":"#/components/schemas/BizBooking"},{"type":"null"}]},"next":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/BizBooking"},{"type":"object","properties":{"inMinutes":{"type":"integer"},"addressNotes":{"type":"string"},"pets":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"services":{"type":"array","items":{"type":"string"}}}}}}}]},{"type":"null"}]}}},"BizServices":{"type":"object","required":["lines"],"properties":{"business":{"$ref":"#/components/schemas/BizRef"},"currency":{"type":"string"},"cardFee":{"type":"string"},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"services":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string"},"active":{"type":"boolean"},"price":{"type":"string"},"priceCents":{"type":"integer"},"durationMin":{"type":"integer"},"groupSize":{"type":"integer"},"tiers":{"type":"array","items":{"type":"object","properties":{"tierIndex":{"type":"integer"},"label":{"type":"string"},"price":{"type":"string"},"priceCents":{"type":"integer"},"durationMin":{"type":"integer"}}}}}}},"packages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"includes":{"type":"array","items":{"type":"string"}},"bundleDiscountPct":{"type":"number"},"active":{"type":"boolean"}}}}}}},"scheduledPriceChanges":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"from":{"type":"string"},"summary":{"type":"string"}}}}}},"BizTimesRequest":{"type":"object","properties":{"bizId":{"$ref":"#/components/schemas/Id","description":"Only when the person runs more than one business (WHICH_BUSINESS lists them)."},"category":{"$ref":"#/components/schemas/Category"},"fromBookingId":{"type":"string","description":"Repeat this booking: same pets, services and length."},"clientId":{"type":"string","description":"With pets[].petKey: the client's known pets."},"pets":{"type":"array","items":{"type":"object","properties":{"petKey":{"type":"string","description":"A known pet of the client (get_client)."},"name":{"type":"string","description":"A new pet's name.","minLength":1,"maxLength":60},"type":{"$ref":"#/components/schemas/PetType"},"weightKg":{"type":"number","exclusiveMinimum":0,"maximum":120},"coat":{"$ref":"#/components/schemas/Coat"},"serviceIds":{"$ref":"#/components/schemas/ServiceIds","description":"The business's service ids (list_business_services); for a known pet, left out = their usual."}},"additionalProperties":false},"maxItems":6},"durationMin":{"type":"integer","description":"Or just a length, in minutes.","minimum":5,"maximum":1440},"resourceId":{"$ref":"#/components/schemas/Id"},"from":{"$ref":"#/components/schemas/Date"},"to":{"$ref":"#/components/schemas/Date"},"windowStart":{"$ref":"#/components/schemas/Time"},"windowEnd":{"$ref":"#/components/schemas/Time"}},"additionalProperties":false},"BizTimes":{"type":"object","required":["days"],"properties":{"business":{"$ref":"#/components/schemas/BizRef"},"category":{"type":"string"},"durationMin":{"type":"integer"},"price":{"type":"string"},"priceCents":{"type":"integer"},"days":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string"},"label":{"type":"string"},"slots":{"type":"array","items":{"type":"object","properties":{"start":{"type":"string"},"time":{"type":"string"},"resourceId":{"type":"string"},"resource":{"type":"string"}}}}}}},"note":{"type":"string"}}},"BizClientBrief":{"type":"object","properties":{"id":{"type":"string","description":"clientId"},"name":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string"},"hasAccount":{"type":"boolean","description":"They use the NogPets app or WhatsApp: NogPets tells them about changes."},"visits":{"type":"integer"},"lastVisit":{"type":["string","null"]},"nextVisit":{"type":["string","null"]},"pets":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"petKey"},"name":{"type":"string"},"type":{"type":"string"},"weightKg":{"type":"number"},"coat":{"type":"string"},"usual":{"type":"string"},"serviceIds":{"type":"array","items":{"type":"string"}}}}},"addresses":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"addressKey"},"label":{"type":"string"},"line1":{"type":"string"},"suburb":{"type":"string"},"postalCode":{"type":"string"},"notes":{"type":"string"}}}},"notes":{"type":"array","items":{"type":"object","properties":{"text":{"type":"string"},"at":{"type":"string"},"by":{"type":"string"}}}},"consent":{"oneOf":[{"type":"object","properties":{"note":{"type":"string"},"at":{"type":"string"}}},{"type":"null"}]},"spent":{"type":"string"}}},"BizClients":{"type":"object","required":["clients"],"properties":{"business":{"$ref":"#/components/schemas/BizRef"},"count":{"type":"integer"},"clients":{"type":"array","items":{"$ref":"#/components/schemas/BizClientBrief"}},"next":{"type":"string"}}},"BizClient":{"type":"object","required":["client"],"properties":{"business":{"$ref":"#/components/schemas/BizRef"},"client":{"$ref":"#/components/schemas/BizClientBrief"},"upcoming":{"type":"array","items":{"$ref":"#/components/schemas/BizBooking"}},"past":{"type":"array","items":{"$ref":"#/components/schemas/BizBooking"}}}},"ClientNoteRequest":{"type":"object","required":["text"],"properties":{"bizId":{"$ref":"#/components/schemas/Id","description":"Only when the person runs more than one business (WHICH_BUSINESS lists them)."},"text":{"type":"string","description":"The note.","minLength":1,"maxLength":1000}},"additionalProperties":false},"ClientNoteResult":{"type":"object","properties":{"business":{"$ref":"#/components/schemas/BizRef"},"clientId":{"type":"string"},"name":{"type":"string"},"notes":{"type":"array","items":{"type":"object","properties":{"text":{"type":"string"},"at":{"type":"string"}}}},"next":{"type":"string"}}},"BizEarnings":{"type":"object","required":["gross","net"],"properties":{"business":{"$ref":"#/components/schemas/BizRef"},"from":{"type":"string"},"to":{"type":"string"},"currency":{"type":"string"},"bookings":{"type":"integer"},"gross":{"$ref":"#/components/schemas/Money"},"fees":{"type":"object","properties":{"total":{"$ref":"#/components/schemas/Money"},"nogpetsCardFee":{"$ref":"#/components/schemas/Money"},"payfast":{"$ref":"#/components/schemas/Money"}}},"net":{"$ref":"#/components/schemas/Money"},"received":{"$ref":"#/components/schemas/Money"},"stillDue":{"$ref":"#/components/schemas/Money"},"refunds":{"type":"object","properties":{"count":{"type":"integer"},"amount":{"$ref":"#/components/schemas/Money"}}},"byService":{"type":"array","items":{"type":"object","properties":{"serviceId":{"type":"string"},"name":{"type":"string"},"count":{"type":"integer"},"cents":{"type":"integer"},"amount":{"type":"string"}}}},"commission":{"description":"The business's NogPets plan; null while none is set."},"notes":{"type":"array","items":{"type":"string"}}}},"BizPayouts":{"type":"object","properties":{"business":{"$ref":"#/components/schemas/BizRef"},"from":{"type":"string"},"to":{"type":"string"},"settlement":{"type":"string"},"cardPayments":{"type":"array","items":{"type":"object","properties":{"bookingId":{"type":["string","null"]},"invoiceId":{"type":"string","description":"An invoice link's payment (create_invoice_link)."},"at":{"type":"string"},"gross":{"type":"string"},"payfastFee":{"type":["string","null"]},"status":{"type":"string"},"paidTo":{"type":"string"}}}},"jobPayouts":{"type":"array","items":{"type":"object","properties":{"bookingId":{"type":"string"},"when":{"type":["string","null"]},"amount":{"type":"string"},"method":{"type":"string"},"status":{"type":"string"},"paidAt":{"type":["string","null"]},"ref":{"type":"string"}}}}}},"BizUnpaid":{"type":"object","required":["bookings"],"properties":{"business":{"$ref":"#/components/schemas/BizRef"},"from":{"type":"string"},"to":{"type":"string"},"count":{"type":"integer"},"total":{"type":"string"},"bookings":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/BizBooking"},{"type":"object","properties":{"overdue":{"type":"boolean"},"owes":{"type":"string"}}}]}},"openInvoices":{"type":"array","description":"Invoice links (create_invoice_link) not paid yet and not expired.","items":{"type":"object","properties":{"invoiceId":{"type":"string"},"description":{"type":"string"},"clientName":{"type":["string","null"]},"total":{"type":"string"},"paymentStatus":{"type":"string"},"expiresAt":{"type":"string"}}}},"next":{"type":"string"}}},"PriceChangeRequest":{"type":"object","required":["changes"],"properties":{"bizId":{"$ref":"#/components/schemas/Id","description":"Only when the person runs more than one business (WHICH_BUSINESS lists them)."},"changes":{"type":"array","items":{"type":"object","required":["serviceId"],"properties":{"serviceId":{"$ref":"#/components/schemas/Id"},"tierIndex":{"type":"integer","description":"The size or coat tier (list_business_services).","minimum":0,"maximum":19},"priceCents":{"type":"integer","description":"The new price in minor units of the business's currency (R650 = 65000).","minimum":0,"maximum":10000000},"percent":{"type":"number","description":"Or move it by a percentage: 10 = up 10%, -5 = down 5% (rounded to whole units).","minimum":-50,"maximum":200},"durationMin":{"type":"integer","description":"A new length, if it changes.","minimum":5,"maximum":1440}},"additionalProperties":false},"minItems":1,"maxItems":40},"effectiveFrom":{"$ref":"#/components/schemas/Date","description":"From this local day (e.g. the 1st of next month); left out, now."},"confirm":{"type":"boolean","description":"true only after the person saw the summary from the first call and said yes."}},"additionalProperties":false},"PriceLine":{"type":"object","properties":{"serviceId":{"type":"string"},"name":{"type":"string"},"tierIndex":{"type":["integer","null"]},"tier":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"},"fromCents":{"type":"integer"},"toCents":{"type":"integer"},"durationMin":{"type":"object","properties":{"from":{"type":"integer"},"to":{"type":"integer"}}}}},"PriceChangeResult":{"type":"object","required":["changes"],"properties":{"business":{"$ref":"#/components/schemas/BizRef"},"scheduled":{"type":"boolean"},"priceChangeId":{"type":"string"},"effectiveFrom":{"type":"string"},"changes":{"type":"array","items":{"$ref":"#/components/schemas/PriceLine"}},"summary":{"type":"string"},"next":{"type":"string"}}},"BizHoursRequest":{"type":"object","required":["week"],"properties":{"bizId":{"$ref":"#/components/schemas/Id","description":"Only when the person runs more than one business (WHICH_BUSINESS lists them)."},"week":{"$ref":"#/components/schemas/Week"},"resourceIds":{"type":"array","items":{"$ref":"#/components/schemas/Id"},"description":"Only these; left out, every van, walker and sitter.","maxItems":20},"confirm":{"type":"boolean","description":"true only after the person saw the summary from the first call and said yes."}},"additionalProperties":false},"BizHoursResult":{"type":"object","properties":{"business":{"$ref":"#/components/schemas/BizRef"},"resourceIds":{"type":"array","items":{"type":"string"}},"week":{"type":"object"},"summary":{"type":"string"},"stillBooked":{"type":"array","items":{"$ref":"#/components/schemas/BizBooking"}},"next":{"type":"string"}}},"TimeOffRequest":{"type":"object","required":["date"],"properties":{"bizId":{"$ref":"#/components/schemas/Id","description":"Only when the person runs more than one business (WHICH_BUSINESS lists them)."},"date":{"$ref":"#/components/schemas/Date"},"toDate":{"$ref":"#/components/schemas/Date","description":"Last whole day, for several days off."},"from":{"$ref":"#/components/schemas/Time"},"to":{"type":"string","pattern":"^(([01][0-9]|2[0-3]):[0-5][0-9]|24:00)$","description":"HH:MM local; left out with from = to the end of the day."},"resourceId":{"$ref":"#/components/schemas/Id","description":"One van, walker or sitter; left out, the whole business."},"reason":{"type":"string","maxLength":200},"confirm":{"type":"boolean","description":"true only after the person saw the summary from the first call and said yes."}},"additionalProperties":false},"TimeOffResult":{"type":"object","required":["timeOffId"],"properties":{"business":{"$ref":"#/components/schemas/BizRef"},"timeOffId":{"type":"string"},"who":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"},"summary":{"type":"string"},"stillBooked":{"type":"array","items":{"$ref":"#/components/schemas/BizBooking"}},"next":{"type":"string"}}},"TimeOffRemoved":{"type":"object","properties":{"business":{"$ref":"#/components/schemas/BizRef"},"removed":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"},"next":{"type":"string"}}},"BizOnly":{"type":"object","properties":{"bizId":{"$ref":"#/components/schemas/Id","description":"Only when the person runs more than one business (WHICH_BUSINESS lists them)."}},"additionalProperties":false},"AreaChangeRequest":{"type":"object","properties":{"bizId":{"$ref":"#/components/schemas/Id","description":"Only when the person runs more than one business (WHICH_BUSINESS lists them)."},"suburbs":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":80},"postalCode":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9 -]{1,9}$"}}},"maxItems":30},"postalCodes":{"type":"array","items":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9 -]{1,9}$"},"maxItems":60},"center":{"type":"object","required":["lat","lng"],"properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"additionalProperties":false},"radiusKm":{"type":"number","exclusiveMinimum":0,"maximum":100},"centerAddress":{"type":"string","description":"Instead of center: a town, suburb or street in the business's country.","minLength":2,"maxLength":200},"centerName":{"type":"string","maxLength":80},"removeAreaIds":{"type":"array","items":{"$ref":"#/components/schemas/Id"},"description":"Areas to stop working in (business_overview's areas).","maxItems":30},"resourceIds":{"type":"array","items":{"$ref":"#/components/schemas/Id"},"description":"Add the new areas to these only; left out, all.","maxItems":20},"confirm":{"type":"boolean","description":"true only after the person saw the summary from the first call and said yes."}},"additionalProperties":false},"AreaChangeResult":{"type":"object","properties":{"business":{"$ref":"#/components/schemas/BizRef"},"added":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}}},"removed":{"type":"array","items":{"type":"string"}},"overlaps":{"type":"array","items":{"type":"object"}},"summary":{"type":"string"},"next":{"type":"string"}}},"PauseRequest":{"type":"object","properties":{"bizId":{"$ref":"#/components/schemas/Id","description":"Only when the person runs more than one business (WHICH_BUSINESS lists them)."},"reason":{"type":"string","description":"Why (for the record and staff).","maxLength":200}},"additionalProperties":false},"ResourceState":{"type":"object","required":["resourceId"],"properties":{"business":{"$ref":"#/components/schemas/BizRef"},"resourceId":{"type":"string"},"name":{"type":"string"},"paused":{"type":"boolean"},"stillBooked":{"type":"array","items":{"$ref":"#/components/schemas/BizBooking"}},"next":{"type":"string"}}},"BizVisitRequest":{"type":"object","required":["category","pets","start","resourceId"],"properties":{"bizId":{"$ref":"#/components/schemas/Id","description":"Only when the person runs more than one business (WHICH_BUSINESS lists them)."},"clientId":{"type":"string","description":"An existing client (find_client)."},"client":{"type":"object","required":["name","phone"],"properties":{"name":{"type":"string","minLength":1,"maxLength":120},"phone":{"type":"string","minLength":6,"maxLength":30},"email":{"type":"string","maxLength":254}},"additionalProperties":false},"consentNote":{"type":"string","description":"New client: how they agreed to be booked and to their details being kept, in the person's words.","maxLength":500},"category":{"$ref":"#/components/schemas/Category"},"pets":{"type":"array","items":{"type":"object","properties":{"petKey":{"type":"string","description":"A known pet of the client (get_client)."},"name":{"type":"string","description":"A new pet's name.","minLength":1,"maxLength":60},"type":{"$ref":"#/components/schemas/PetType"},"weightKg":{"type":"number","exclusiveMinimum":0,"maximum":120},"coat":{"$ref":"#/components/schemas/Coat"},"serviceIds":{"$ref":"#/components/schemas/ServiceIds","description":"The business's service ids (list_business_services); for a known pet, left out = their usual."}},"additionalProperties":false},"minItems":1,"maxItems":6},"addressKey":{"type":"string","description":"One of the client's addresses (get_client)."},"address":{"type":"object","required":["line1"],"properties":{"label":{"type":"string","maxLength":40},"line1":{"type":"string","minLength":1,"maxLength":200},"suburb":{"type":"string","maxLength":80},"postalCode":{"type":"string","maxLength":12},"notes":{"type":"string","description":"Gate code, parking.","maxLength":300},"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"additionalProperties":false},"start":{"type":"string","description":"From find_business_times (ISO).","format":"date-time"},"resourceId":{"$ref":"#/components/schemas/Id"},"paymentMethod":{"type":"string","enum":["CASH","CARD"],"description":"CASH on the day, or CARD: a Payfast link for the client."},"notes":{"type":"string","maxLength":1000},"confirm":{"type":"boolean","description":"true only after the person saw the summary from the first call and said yes."}},"additionalProperties":false},"BizVisitResult":{"type":"object","required":["bookingId"],"properties":{"bookingId":{"type":"string"},"status":{"type":"string"},"when":{"type":"string"},"start":{"type":"string"},"resourceId":{"type":"string"},"paymentMethod":{"type":"string"},"total":{"type":"string"},"totalCents":{"type":"integer"},"summary":{"type":"string"},"payUrl":{"type":["string","null"],"description":"CARD: the client's Payfast link (48 hours)."},"clientId":{"type":"string"},"repeatOf":{"type":"string"},"next":{"type":"string"}}},"RepeatRequest":{"type":"object","required":["start"],"properties":{"bizId":{"$ref":"#/components/schemas/Id","description":"Only when the person runs more than one business (WHICH_BUSINESS lists them)."},"start":{"type":"string","description":"From find_business_times with fromBookingId.","format":"date-time"},"resourceId":{"$ref":"#/components/schemas/Id"},"paymentMethod":{"type":"string","enum":["CASH","CARD"]},"notes":{"type":"string","maxLength":1000},"confirm":{"type":"boolean","description":"true only after the person saw the summary from the first call and said yes."}},"additionalProperties":false},"BizPayLink":{"type":"object","required":["payUrl"],"properties":{"business":{"$ref":"#/components/schemas/BizRef"},"bookingId":{"type":"string"},"total":{"type":"string"},"totalCents":{"type":"integer"},"payUrl":{"type":"string"},"expiresAt":{"type":"string"},"sent":{"type":"object","properties":{"whatsapp":{"type":"string","description":"sent, stubbed, off (not on WhatsApp), duplicate (sent before), no-account, failed…"}}},"next":{"type":"string"}}},"InvoiceRequest":{"type":"object","required":["amountCents","description"],"properties":{"bizId":{"$ref":"#/components/schemas/Id","description":"Only when the person runs more than one business (WHICH_BUSINESS lists them)."},"amountCents":{"type":"integer","minimum":500,"maximum":5000000,"description":"The amount in the business's currency, minor units (R350 = 35000). NogPets' card fee is added on top for the client."},"description":{"type":"string","minLength":1,"maxLength":100,"description":"What it's for, shown to the client on the pay page, e.g. \"Nail clip for Max\"."},"clientName":{"type":"string","maxLength":120},"clientId":{"type":"string","description":"A client of the business (find_client), for the name and the record."},"bookingId":{"type":"string","description":"A booking of the business this payment goes with, as a reference only (an unpaid card booking has its own link, send_payment_link)."},"expiresInDays":{"type":"integer","minimum":1,"maximum":30,"description":"How long the link works (default 7)."},"confirm":{"type":"boolean","description":"true only after the person saw the summary from the first call and said yes."}},"additionalProperties":false},"InvoiceLink":{"type":"object","required":["invoiceId","payUrl","qrUrl"],"properties":{"business":{"$ref":"#/components/schemas/BizRef"},"invoiceId":{"type":"string"},"description":{"type":"string"},"amount":{"type":"string"},"amountCents":{"type":"integer"},"cardFee":{"type":"string"},"total":{"type":"string","description":"What the client pays (the amount + NogPets' card fee)."},"totalCents":{"type":"integer"},"clientName":{"type":["string","null"]},"payUrl":{"type":"string","description":"The page the client opens to pay on Payfast (https://api.nogpets.com/pay/i/{id}?t=…)."},"qrUrl":{"type":"string","description":"A PNG QR code of payUrl, to show or print for the client to scan."},"expiresAt":{"type":"string"},"summary":{"type":"string"},"next":{"type":"string"}}},"MoveRequest":{"type":"object","required":["start"],"properties":{"bizId":{"$ref":"#/components/schemas/Id","description":"Only when the person runs more than one business (WHICH_BUSINESS lists them)."},"start":{"type":"string","description":"The new start (ISO).","format":"date-time"},"resourceId":{"$ref":"#/components/schemas/Id"},"confirm":{"type":"boolean","description":"true only after the person saw the summary from the first call and said yes."}},"additionalProperties":false},"MoveResult":{"type":"object","required":["bookingId"],"properties":{"business":{"$ref":"#/components/schemas/BizRef"},"bookingId":{"type":"string"},"from":{"type":"string"},"start":{"type":"string"},"when":{"type":"string"},"resourceId":{"type":"string"},"status":{"type":"string"},"paymentStatus":{"type":"string"},"summary":{"type":"string"},"next":{"type":"string"}}},"BizCancelRequest":{"type":"object","properties":{"bizId":{"$ref":"#/components/schemas/Id","description":"Only when the person runs more than one business (WHICH_BUSINESS lists them)."},"series":{"type":"boolean","description":"Also the rest of its repeats."},"reason":{"type":"string","maxLength":300},"confirm":{"type":"boolean","description":"true only after the person saw the summary from the first call and said yes."}},"additionalProperties":false},"BizCancelResult":{"type":"object","required":["cancelled"],"properties":{"business":{"$ref":"#/components/schemas/BizRef"},"cancelled":{"type":"array","items":{"type":"string"}},"refundsRequested":{"type":"array","items":{"type":"string"}},"summary":{"type":"string"},"next":{"type":"string"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Stable, upper-case."},"message":{"type":"string","description":"Short and human; safe to show."},"details":{"type":"object","additionalProperties":true}}}}},"Date":{"type":"string","pattern":"^[0-9]{4}-[0-9]{2}-[0-9]{2}$","description":"A local date, YYYY-MM-DD."},"Time":{"type":"string","pattern":"^([01][0-9]|2[0-3]):[0-5][0-9]$","description":"A local time of day, HH:MM."},"Category":{"type":"string","pattern":"^[a-z0-9_-]{1,40}$","description":"A service line id: grooming, walking or sitting.","examples":["grooming"]},"PetType":{"type":"string","enum":["DOG","CAT"]},"Coat":{"type":"string","enum":["SHORT","MEDIUM","LONG"]},"BookingStatus":{"type":"string","enum":["PENDING","ACCEPTED","REJECTED","CANCELLED","COMPLETED"]},"PaymentStatus":{"type":"string","enum":["PENDING","PAID","CASH_DUE","CASH_RECEIVED","REFUND_REQUESTED","REFUNDED","FAILED"]},"ServiceIds":{"type":"array","minItems":1,"maxItems":10,"items":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$"},"description":"Service ids from list_services; exactly one PRIMARY plus any EXTRAs of the same line. A package id (a line's `packages`) stands for its main service and extras."},"Package":{"type":"object","required":["id","name","includes","fromCents","toCents"],"description":"A main service and extras in one choice, priced from its parts for the pet (their tiers), less bundleDiscountPct.","properties":{"id":{"type":"string"},"name":{"type":"string"},"blurb":{"type":"string"},"includes":{"type":"array","items":{"type":"string"},"description":"Service ids: one PRIMARY and EXTRAs."},"bundleDiscountPct":{"type":"number"},"petTypes":{"type":"array","items":{"$ref":"#/components/schemas/PetType"}},"fromCents":{"type":"integer"},"toCents":{"type":"integer"}}},"Tier":{"type":"object","properties":{"petType":{"$ref":"#/components/schemas/PetType"},"coat":{"$ref":"#/components/schemas/Coat"},"minKg":{"type":"number"},"maxKg":{"type":"number"},"priceCents":{"type":"integer"},"durationMin":{"type":"integer"}}},"Service":{"type":"object","required":["id","name","kind","priceCents","durationMin","fromCents","toCents"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["PRIMARY","EXTRA"]},"blurb":{"type":"string"},"petTypes":{"type":"array","items":{"$ref":"#/components/schemas/PetType"}},"priceCents":{"type":"integer","description":"Base price when no tier matches."},"durationMin":{"type":"integer"},"fromCents":{"type":"integer"},"toCents":{"type":"integer"},"groupSize":{"type":"integer","description":"More than 1 is a group walk sharing the slot."},"tiers":{"type":"array","items":{"$ref":"#/components/schemas/Tier"}}}},"Services":{"type":"object","required":["currency","serviceFeeCents","acceptsCash","areas","lines"],"properties":{"currency":{"type":"string","const":"ZAR"},"serviceFeeCents":{"type":"integer","description":"Added to card payments only."},"acceptsCash":{"type":"boolean"},"areas":{"type":"array","items":{"type":"string"},"description":"Suburbs we cover."},"lines":{"type":"array","items":{"type":"object","required":["id","label","services"],"properties":{"id":{"type":"string"},"label":{"type":"string"},"blurb":{"type":"string"},"durationMode":{"type":"string","enum":["SUM","MAX"],"description":"SUM: pets one after the other; MAX: together."},"repeats":{"type":"boolean","description":"Can repeat weekly."},"services":{"type":"array","items":{"$ref":"#/components/schemas/Service"}},"packages":{"type":"array","items":{"$ref":"#/components/schemas/Package"}}}}}}},"Place":{"type":"object","properties":{"suburb":{"type":["string","null"]},"postalCode":{"type":["string","null"]},"lat":{"type":["number","null"]},"lng":{"type":["number","null"]},"town":{"type":["string","null"],"description":"Abroad: the town it was found in."},"country":{"type":"string","description":"Abroad only: ISO 3166 code of the place's country."}}},"LineCoverage":{"type":"object","required":["id","label","covered"],"properties":{"id":{"type":"string"},"label":{"type":"string"},"covered":{"type":"boolean"}}},"Coverage":{"type":"object","required":["covered","lines"],"properties":{"covered":{"type":"boolean"},"error":{"type":"string","enum":["NO_COVERAGE","UNKNOWN_PLACE"]},"leadId":{"type":["string","null"],"description":"NO_COVERAGE: the request is kept so our team can follow up."},"message":{"type":"string","description":"NO_COVERAGE: what to tell the person."},"next":{"type":"string","description":"NO_COVERAGE: what to do (say it plainly; promise nothing)."},"place":{"oneOf":[{"$ref":"#/components/schemas/Place"},{"type":"null"}]},"lines":{"type":"array","items":{"$ref":"#/components/schemas/LineCoverage"}},"nearest":{"oneOf":[{"type":"null"},{"type":"object","properties":{"name":{"type":"string"},"distanceKm":{"type":"number"}}}]}}},"PetLine":{"type":"object","additionalProperties":false,"required":["serviceIds"],"description":"A saved pet (`petId`, needs a token) or one described by value (`name`, `type`, `weightKg`, `coat`).","properties":{"petId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$"},"name":{"type":"string","minLength":1,"maxLength":60},"type":{"$ref":"#/components/schemas/PetType"},"weightKg":{"type":"number","exclusiveMinimum":0,"exclusiveMaximum":120},"coat":{"$ref":"#/components/schemas/Coat"},"serviceIds":{"$ref":"#/components/schemas/ServiceIds"},"packageId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$","description":"A package from list_services (same as putting it in serviceIds)."}}},"QuoteRequest":{"type":"object","additionalProperties":false,"required":["category","pets"],"properties":{"category":{"$ref":"#/components/schemas/Category"},"address":{"type":"string","maxLength":300,"description":"Typed address with the suburb or postal code, or \"lat,lng\"."},"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180},"postalCode":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9 -]{1,9}$"},"addressId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$","description":"A saved address (needs a token with the addresses scope)."},"pets":{"type":"array","minItems":1,"maxItems":6,"items":{"$ref":"#/components/schemas/PetLine"}},"promoCode":{"type":"string","maxLength":32,"description":"A promo code (e.g. WELCOME30). Leave it out to apply a code the person claimed on nogpets.com (matched by their mobile); send \"\" for none."}}},"TimesRequest":{"type":"object","additionalProperties":false,"required":["category","pets"],"properties":{"category":{"$ref":"#/components/schemas/Category"},"address":{"type":"string","maxLength":300},"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180},"postalCode":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9 -]{1,9}$"},"addressId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$"},"pets":{"type":"array","minItems":1,"maxItems":6,"items":{"$ref":"#/components/schemas/PetLine"}},"from":{"$ref":"#/components/schemas/Date"},"to":{"$ref":"#/components/schemas/Date"},"windowStart":{"$ref":"#/components/schemas/Time"},"windowEnd":{"$ref":"#/components/schemas/Time"},"stay":{"$ref":"#/components/schemas/Stay"},"visits":{"$ref":"#/components/schemas/Visits"},"promoCode":{"type":"string","maxLength":32,"description":"A promo code (e.g. WELCOME30). Leave it out to apply a code the person claimed on nogpets.com (matched by their mobile); send \"\" for none."}}},"Item":{"type":"object","required":["serviceId","name","kind","priceCents","durationMin"],"properties":{"serviceId":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["PRIMARY","EXTRA"]},"priceCents":{"type":"integer"},"durationMin":{"type":"integer"}}},"Quote":{"type":"object","required":["category","durationMin","pets","subtotalCents","cardFeeCents","cardTotalCents","acceptsCash","summary"],"properties":{"category":{"type":"string"},"durationMin":{"type":"integer"},"pets":{"type":"array","items":{"type":"object","required":["name","items"],"properties":{"petId":{"type":"string"},"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/Item"}},"package":{"type":"object","description":"The package chosen; items are its parts at list price and savingCents comes off.","properties":{"id":{"type":"string"},"name":{"type":"string"},"savingCents":{"type":"integer"}}}}}},"subtotalCents":{"type":"integer"},"cardFeeCents":{"type":"integer"},"cardTotalCents":{"type":"integer"},"cashTotalCents":{"type":["integer","null"],"description":"Null when cash isn't taken. After the discount."},"discount":{"description":"The promo code applied (cardTotalCents and cashTotalCents are after it). `auto` when it came from the person's claimed offer.","oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Discount"}]},"discountError":{"type":["string","null"],"enum":["UNKNOWN","INACTIVE","NOT_STARTED","EXPIRED","USED_UP","NOT_APPLICABLE","NOT_FIRST","LIMIT_REACHED","MIN_SUBTOTAL",null],"description":"Why promoCode can't be used. The quote is then without it."},"acceptsCash":{"type":"boolean"},"group":{"type":["object","null"],"description":"A group walk: {serviceId, size, dogs}."},"summary":{"type":"string"}}},"Slot":{"type":"object","required":["start","time","resourceId"],"properties":{"start":{"type":"string","format":"date-time"},"time":{"type":"string","description":"Local HH:MM."},"resourceId":{"type":"string"}}},"Day":{"type":"object","required":["date","label","slots"],"properties":{"date":{"$ref":"#/components/schemas/Date"},"label":{"type":"string","examples":["Tue 29 Sep"]},"slots":{"type":"array","items":{"$ref":"#/components/schemas/Slot"}}}},"Times":{"type":"object","required":["durationMin","quote","days"],"properties":{"error":{"type":"string","enum":["NO_AVAILABILITY"]},"reason":{"type":"string","enum":["OUTSIDE_HOURS","CLOSED_DAY","FULLY_BOOKED"],"description":"NO_AVAILABILITY: why nothing is open then. OUTSIDE_HOURS: the service can't fit inside working hours or the window asked; CLOSED_DAY: nobody works that day; FULLY_BOOKED: it fits but every time is taken."},"alternatives":{"type":"array","description":"NO_AVAILABILITY: the next open times (up to 5, within 14 days). Offer these; book with start and resourceId unchanged.","items":{"type":"object","properties":{"label":{"type":"string","examples":["Sun 4 Oct 09:00"]},"date":{"$ref":"#/components/schemas/Date"},"start":{"type":"string","format":"date-time"},"resourceId":{"type":"string"}}}},"next":{"type":"string","description":"NO_AVAILABILITY: what to do next."},"leadId":{"type":["string","null"],"description":"NO_AVAILABILITY with no alternatives: the request is kept so our team or a partner can come back to the person."},"message":{"type":"string","description":"NO_AVAILABILITY: what to tell the person: the real reason and the next open times, or (none in 14 days) that we'll find someone."},"durationMin":{"type":"integer"},"quote":{"$ref":"#/components/schemas/Quote"},"days":{"type":"array","items":{"$ref":"#/components/schemas/Day"}},"mode":{"type":"string","enum":["SLOT","STAY"],"description":"STAY: an overnight service; book it with `stay`, not a start time."},"multiDay":{"type":"boolean","description":"The service can also be booked as visits over several days (`visits`)."},"windows":{"type":["object","null"],"description":"The windows to offer: STAY {evening, morning}, multiDay {visit}; each [{id, label, start, end, text}]."},"plan":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Plan"}]}}},"Stay":{"type":"object","additionalProperties":false,"required":["startDate","nights"],"description":"An overnight stay. One booking a night, from the evening visit to the next morning's check.","properties":{"startDate":{"$ref":"#/components/schemas/Date"},"nights":{"type":"integer","minimum":1,"maximum":14},"eveningWindow":{"type":"string","description":"A window id from `windows.evening` (or \"17:00-19:00\"). Default the first."},"morningWindow":{"type":"string","description":"A window id from `windows.morning`. Default the first."},"notes":{"type":"string","maxLength":1000,"description":"Keys, feeding, meds."}}},"Visits":{"type":"object","additionalProperties":false,"required":["startDate","days"],"description":"Visits over several days. One booking a visit, at the first free time in its window.","properties":{"startDate":{"$ref":"#/components/schemas/Date"},"days":{"type":"integer","minimum":1,"maximum":14},"perDay":{"type":"integer","minimum":1,"maximum":3},"windows":{"type":"array","maxItems":3,"items":{"type":"string"},"description":"A window id from `windows.visit` per visit of the day, in order."},"notes":{"type":"string","maxLength":1000}}},"Plan":{"type":"object","required":["mode","label","ok","spans"],"properties":{"mode":{"type":"string","enum":["STAY","MULTI_VISIT"]},"label":{"type":"string","examples":["3 nights, 12–15 Oct, evening visits 17:00–19:00, morning checks 07:00–09:00"]},"ok":{"type":"boolean","description":"Every night or visit has a free sitter."},"spans":{"type":"array","items":{"type":"object","properties":{"date":{"$ref":"#/components/schemas/Date"},"start":{"type":["string","null"],"format":"date-time"},"end":{"type":["string","null"],"format":"date-time"},"window":{"type":"string"},"free":{"type":"boolean"}}}}}},"Profile":{"type":"object","required":["uid","name","scopes"],"properties":{"uid":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"pets":{"type":"integer"},"addresses":{"type":"integer"},"client":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}},"scopes":{"type":"array","items":{"type":"string"}}}},"Pet":{"type":"object","required":["id","name","type","weightKg","coat"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"$ref":"#/components/schemas/PetType"},"breed":{"type":"string"},"weightKg":{"type":"number"},"coat":{"$ref":"#/components/schemas/Coat"},"birthYear":{"type":["integer","null"]},"notes":{"type":"string"}}},"NewPet":{"type":"object","additionalProperties":false,"required":["name","type","weightKg","coat"],"properties":{"name":{"type":"string","minLength":1,"maxLength":60},"type":{"$ref":"#/components/schemas/PetType"},"weightKg":{"type":"number","exclusiveMinimum":0,"exclusiveMaximum":120},"coat":{"$ref":"#/components/schemas/Coat"},"breed":{"type":"string","maxLength":80},"birthYear":{"type":"integer","minimum":1990,"maximum":2100},"notes":{"type":"string","maxLength":1000}}},"Address":{"type":"object","required":["id","label","line1"],"properties":{"id":{"type":"string"},"label":{"type":"string"},"line1":{"type":"string"},"suburb":{"type":"string"},"city":{"type":"string"},"postalCode":{"type":"string"},"notes":{"type":"string"},"isDefault":{"type":"boolean"}}},"NewAddress":{"type":"object","additionalProperties":false,"required":["label","line1"],"properties":{"label":{"type":"string","minLength":1,"maxLength":40},"line1":{"type":"string","minLength":1,"maxLength":200},"suburb":{"type":"string","maxLength":80},"city":{"type":"string","maxLength":80},"postalCode":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9 -]{1,9}$"},"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180},"notes":{"type":"string","maxLength":500},"isDefault":{"type":"boolean"}}},"BookRequest":{"type":"object","additionalProperties":false,"required":["category","addressId","pets","paymentMethod"],"description":"One visit: start and resourceId from find_times. An overnight stay: `stay`. Visits over several days: `visits`.","properties":{"category":{"$ref":"#/components/schemas/Category"},"addressId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$"},"pets":{"type":"array","minItems":1,"maxItems":6,"items":{"type":"object","additionalProperties":false,"required":["petId","serviceIds"],"properties":{"petId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$"},"serviceIds":{"$ref":"#/components/schemas/ServiceIds"},"packageId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$"}}}},"start":{"type":"string","format":"date-time","description":"A slot's start from find_times, unchanged."},"resourceId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$","description":"The slot's resourceId, unchanged."},"paymentMethod":{"type":"string","enum":["CARD","CASH"]},"notes":{"type":"string","maxLength":1000},"repeat":{"type":"object","additionalProperties":false,"required":["freq","days"],"description":"Walks only. Books the weeks up to 4 weeks out now; the rest follow.","properties":{"freq":{"type":"string","const":"WEEKLY"},"days":{"type":"array","minItems":1,"maxItems":7,"items":{"type":"string","enum":["mon","tue","wed","thu","fri","sat","sun"]}},"until":{"oneOf":[{"$ref":"#/components/schemas/Date"},{"type":"null"}]}}},"confirm":{"type":"boolean","description":"Cash only: true once the person said yes to the summary."},"stay":{"$ref":"#/components/schemas/Stay"},"visits":{"$ref":"#/components/schemas/Visits"},"promoCode":{"type":"string","maxLength":32,"description":"The code from the quote. A code that no longer applies is a 409 PROMO (details.reason). Left out, a claimed offer is applied if it fits."}}},"Discount":{"type":"object","required":["code","amountCents"],"properties":{"code":{"type":"string","examples":["WELCOME30"]},"amountCents":{"type":"integer","description":"What came off the price (never the card fee)."},"auto":{"type":"boolean"}}},"BookResult":{"type":"object","required":["bookingId","bookingIds","status","paymentMethod","paymentStatus","totalCents","total","start","when","payUrl","next"],"properties":{"bookingId":{"type":"string"},"bookingIds":{"type":"array","items":{"type":"string"},"description":"Every week booked (repeats)."},"seriesId":{"type":["string","null"]},"status":{"$ref":"#/components/schemas/BookingStatus"},"paymentMethod":{"type":"string","enum":["CARD","CASH"]},"paymentStatus":{"$ref":"#/components/schemas/PaymentStatus"},"totalCents":{"type":"integer"},"total":{"type":"string"},"discount":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Discount"}]},"plan":{"type":["object","null"],"description":"A stay or visits over days: {mode, label, count}."},"start":{"type":"string","format":"date-time"},"when":{"type":"string"},"skipped":{"type":"array","items":{"type":"string","format":"date-time"},"description":"Repeat weeks that were full."},"payUrl":{"type":["string","null"],"format":"uri","description":"Card: the link the person opens to pay (48 hours)."},"next":{"type":"string","description":"What to tell the person."}}},"Booking":{"type":"object","required":["id","category","start","status","paymentStatus","paymentMethod","totalCents"],"properties":{"id":{"type":"string"},"category":{"type":"string"},"what":{"type":"string","examples":["Biscuit: Full groom, Nails"]},"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"},"when":{"type":"string"},"address":{"type":"object","properties":{"label":{"type":"string"},"line1":{"type":"string"},"suburb":{"type":"string"},"mapUrl":{"type":["string","null"],"description":"The address on Google Maps."}}},"status":{"$ref":"#/components/schemas/BookingStatus"},"paymentMethod":{"type":"string","enum":["CARD","CASH"]},"paymentStatus":{"$ref":"#/components/schemas/PaymentStatus"},"totalCents":{"type":"integer"},"total":{"type":"string"},"discount":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Discount"}]},"crew":{"type":"array","items":{"type":"string"}},"seriesId":{"type":["string","null"]},"canPay":{"type":"boolean"},"source":{"type":"string"}}},"Variant":{"type":"object","required":["id","label","priceCents","inStock"],"properties":{"id":{"type":"string"},"label":{"type":"string"},"priceCents":{"type":"integer"},"inStock":{"type":"boolean"}}},"Product":{"type":"object","required":["id","name","category","priceCents","inStock"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"category":{"type":"string"},"blurb":{"type":"string"},"petTypes":{"type":"array","items":{"type":"string"}},"priceCents":{"type":"integer"},"compareAtCents":{"type":["integer","null"]},"variants":{"type":"array","items":{"$ref":"#/components/schemas/Variant"}},"inStock":{"type":"boolean"},"deliverWithVisit":{"type":"boolean"},"image":{"type":["string","null"],"format":"uri"},"contents":{"type":"array","description":"A box's contents (bundles only); it's in stock when every item is.","items":{"type":"object","required":["productId","name","qty"],"properties":{"productId":{"type":"string"},"name":{"type":"string"},"variantLabel":{"type":"string"},"qty":{"type":"integer"}}}}}},"ShippingMethod":{"type":"object","required":["id","label","feeCents"],"properties":{"id":{"type":"string"},"label":{"type":"string"},"feeCents":{"type":"integer"},"eta":{"type":"string"},"postalCodes":{"type":"array","items":{"type":"string"}}}},"Catalogue":{"type":"object","required":["products","shipping"],"properties":{"products":{"type":"array","items":{"$ref":"#/components/schemas/Product"}},"shipping":{"type":"array","items":{"$ref":"#/components/schemas/ShippingMethod"}},"freeShippingOverCents":{"type":["integer","null"]},"note":{"type":"string"}}},"OrderItem":{"type":"object","additionalProperties":false,"required":["productId","qty"],"properties":{"productId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$"},"variantId":{"type":"string","maxLength":64},"qty":{"type":"integer","minimum":1,"maximum":20}}},"OrderQuoteRequest":{"type":"object","additionalProperties":false,"required":["items","shippingMethod"],"properties":{"items":{"type":"array","minItems":1,"maxItems":20,"items":{"$ref":"#/components/schemas/OrderItem"}},"shippingMethod":{"type":"string","maxLength":40,"examples":["courier","local","visit"]},"postalCode":{"type":"string","pattern":"^[0-9]{4}$"},"bookingId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$"},"discountCode":{"type":"string","maxLength":32}}},"OrderQuote":{"type":"object","required":["items","subtotalCents","shippingCents","totalCents","problems","ok"],"properties":{"items":{"type":"array","items":{"type":"object"}},"subtotalCents":{"type":"integer"},"discount":{"type":["object","null"]},"discountError":{"type":["string","null"]},"shippingMethod":{"type":["string","null"]},"shipping":{"type":["object","null"]},"shippingCents":{"type":"integer"},"shippingError":{"type":["string","null"]},"totalCents":{"type":"integer"},"problems":{"type":"array","items":{"type":"object"}},"ok":{"type":"boolean"}}},"ShipTo":{"type":"object","additionalProperties":false,"required":["line1","city","postalCode"],"properties":{"line1":{"type":"string","maxLength":200},"suburb":{"type":"string","maxLength":80},"city":{"type":"string","maxLength":80},"province":{"type":"string","maxLength":40},"postalCode":{"type":"string","pattern":"^[0-9]{4}$"},"notes":{"type":"string","maxLength":500}}},"OrderRequest":{"type":"object","additionalProperties":false,"required":["items","shippingMethod"],"properties":{"items":{"type":"array","minItems":1,"maxItems":20,"items":{"$ref":"#/components/schemas/OrderItem"}},"shippingMethod":{"type":"string","maxLength":40},"postalCode":{"type":"string","pattern":"^[0-9]{4}$"},"bookingId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$"},"discountCode":{"type":"string","maxLength":32},"shipTo":{"$ref":"#/components/schemas/ShipTo"},"paymentMethod":{"type":"string","enum":["CARD","CASH"],"default":"CARD"},"confirm":{"type":"boolean","description":"Cash only: true once the person said yes."}}},"OrderResult":{"type":"object","required":["orderId","number","status","totalCents","total","payUrl","next"],"properties":{"orderId":{"type":"string"},"number":{"type":"string","examples":["NP-1004"]},"status":{"type":"string"},"totalCents":{"type":"integer"},"total":{"type":"string"},"payUrl":{"type":["string","null"],"format":"uri","description":"The order's page; a Pay button while unpaid."},"next":{"type":"string"}}},"DirectoryCategory":{"type":"string","enum":["GROOMER_SALON","GROOMER_MOBILE","PET_STORE","VET","BOARDING","DAYCARE","WALKER","TRAINER","ANIMAL_WELFARE"]},"Listing":{"type":"object","required":["id","name","town","categories","url"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"town":{"type":"string"},"suburb":{"type":"string"},"address":{"type":"string"},"categories":{"type":"array","items":{"$ref":"#/components/schemas/DirectoryCategory"}},"services":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"priceText":{"type":"string"}}}},"petTypes":{"type":"array","items":{"type":"string"}},"phone":{"type":"string"},"website":{"type":"string"},"hoursText":{"type":"string"},"blurb":{"type":"string"},"isNogPets":{"type":"boolean"},"partner":{"type":"boolean","description":"On NogPets: an approved NogPets business (or NogPets itself). Listed first."},"bookWith":{"type":"string","description":"For a business on NogPets: how to book it through NogPets."},"verified":{"type":"boolean"},"lastChecked":{"type":["string","null"],"format":"date"},"url":{"type":"string","format":"uri","description":"The listing on nogpets.com."}}},"ApplicationStatus":{"type":"string","enum":["DRAFT","SUBMITTED","APPROVED","REJECTED"],"description":"DRAFT while it's being filled in; SUBMITTED while NogPets reviews it; APPROVED (the business exists, bizId) or REJECTED (reviewNote says why; editing it makes it a DRAFT again)."},"LineId":{"type":"string","enum":["grooming","walking","sitting"],"description":"A NogPets service line."},"Week":{"type":"object","additionalProperties":false,"description":"Working hours per weekday, local time. Leave out days off.","properties":{"mon":{"$ref":"#/components/schemas/DayRanges"},"tue":{"$ref":"#/components/schemas/DayRanges"},"wed":{"$ref":"#/components/schemas/DayRanges"},"thu":{"$ref":"#/components/schemas/DayRanges"},"fri":{"$ref":"#/components/schemas/DayRanges"},"sat":{"$ref":"#/components/schemas/DayRanges"},"sun":{"$ref":"#/components/schemas/DayRanges"}}},"DayRanges":{"type":"array","maxItems":6,"items":{"type":"object","additionalProperties":false,"required":["start","end"],"properties":{"start":{"$ref":"#/components/schemas/Time"},"end":{"$ref":"#/components/schemas/Time"}}}},"BusinessDetails":{"type":"object","additionalProperties":false,"description":"New application: businessName, categories, town and a phone or email are required. With applicationId: only what changes.","properties":{"applicationId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$","description":"Update this application instead of starting one."},"businessName":{"type":"string","minLength":1,"maxLength":120,"description":"The registered or main business name."},"tradingName":{"type":"string","maxLength":120,"description":"The name clients know, if different."},"contactName":{"type":"string","maxLength":120,"description":"The owner or the person NogPets talks to."},"phone":{"type":"string","maxLength":30,"description":"With its country code (+1 512 555 0100), or national for the business's country (082 555 0101 in South Africa); stored as E.164."},"email":{"type":"string","maxLength":254},"website":{"type":"string","maxLength":300},"town":{"type":"string","minLength":1,"maxLength":80,"description":"Where the business is based, e.g. Somerset West, Austin TX, Manchester."},"country":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO 3166-1 alpha-2 code of the country the business is in: ZA, US, GB, AU, DE… Required for a new application unless the phone's country code says it."},"currency":{"type":"string","pattern":"^[A-Za-z]{3}$","description":"ISO 4217 code the business charges in (ZAR, USD, GBP, EUR…). Defaults from the country; prices are in its minor units."},"timezone":{"type":"string","maxLength":64,"description":"IANA time zone of its hours, e.g. America/Chicago. Defaults when the country has one zone."},"payoutPreference":{"oneOf":[{"type":"null"},{"type":"object","additionalProperties":false,"required":["method"],"description":"Outside South Africa: how they'd like to be paid, for NogPets to arrange after approval. Information only: never account numbers, IBANs, cards, keys or passwords (refused).","properties":{"method":{"type":"string","enum":["BANK_TRANSFER","PAYPAL","STRIPE","WISE","CASH","OTHER"]},"note":{"type":"string","maxLength":200,"description":"A few words, e.g. \"ACH in USD\" or \"PayPal business account\"."}}}]},"suburbs":{"type":"array","maxItems":40,"items":{"type":"string","maxLength":80},"description":"Suburbs they serve, as they say them (set_service_area makes them bookable areas)."},"categories":{"type":"array","minItems":1,"maxItems":3,"items":{"$ref":"#/components/schemas/LineId"}},"mode":{"type":"string","enum":["MOBILE","SALON","BOTH"],"description":"MOBILE goes to the client (what NogPets books today); SALON is at their premises; BOTH."},"vans":{"type":"integer","minimum":0,"maximum":100},"staff":{"type":"integer","minimum":0,"maximum":500},"about":{"type":"string","maxLength":300,"description":"One or two plain sentences about the business."},"claimListingId":{"type":"string","pattern":"^([a-z0-9-]{1,120})?$","description":"A directory listing id (from possibleListings or find_pet_businesses) this business owns; \"\" unclaims."},"whatsappOptIn":{"type":"boolean","description":"The owner agrees to NogPets WhatsApp messages about the application."}}},"TierIn":{"type":"object","additionalProperties":false,"required":["priceCents"],"properties":{"petType":{"$ref":"#/components/schemas/PetType"},"coat":{"$ref":"#/components/schemas/Coat"},"minKg":{"type":"number","minimum":0,"maximum":200},"maxKg":{"type":"number","minimum":0,"maximum":200},"priceCents":{"type":"integer","minimum":0,"maximum":10000000},"durationMin":{"type":"integer","minimum":5,"maximum":1440}}},"NewBusinessService":{"type":"object","additionalProperties":false,"required":["category","kind","name","priceCents","durationMin"],"properties":{"id":{"type":"string","pattern":"^[a-z0-9-]{1,60}$","description":"An existing service's id, to replace it."},"category":{"$ref":"#/components/schemas/LineId"},"kind":{"type":"string","enum":["PRIMARY","EXTRA"]},"name":{"type":"string","minLength":1,"maxLength":80},"blurb":{"type":"string","maxLength":300},"petTypes":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/PetType"}},"priceCents":{"type":"integer","minimum":0,"maximum":10000000,"description":"In the business's currency, minor units (cents); the price when no tier matches."},"durationMin":{"type":"integer","minimum":5,"maximum":1440},"tiers":{"type":"array","maxItems":20,"items":{"$ref":"#/components/schemas/TierIn"}},"groupSize":{"type":"integer","minimum":1,"maximum":20,"description":"Walks: more than 1 lets that many dogs share a slot."},"sort":{"type":"integer","minimum":0,"maximum":999}}},"BusinessServicesRequest":{"type":"object","additionalProperties":false,"properties":{"services":{"type":"array","maxItems":60,"items":{"$ref":"#/components/schemas/NewBusinessService"}},"useTemplate":{"type":"boolean","description":"Copy NogPets' own menu for the business's lines first."},"templateCategories":{"type":"array","items":{"$ref":"#/components/schemas/LineId"},"description":"Only these lines from the template."},"priceAdjustPct":{"type":"integer","minimum":-50,"maximum":200,"description":"ZAR businesses: move the template's prices by this percentage (rounded to R5)."},"replace":{"type":"boolean","description":"Drop the services there first."},"removeIds":{"type":"array","maxItems":60,"items":{"type":"string","maxLength":60}}}},"ServiceAreaRequest":{"type":"object","additionalProperties":false,"properties":{"suburbs":{"type":"array","maxItems":30,"items":{"oneOf":[{"type":"string","minLength":1,"maxLength":80},{"type":"object","additionalProperties":false,"required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":80},"postalCode":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9 -]{1,9}$"}}}]}},"postalCodes":{"type":"array","maxItems":60,"items":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9 -]{1,9}$"}},"center":{"type":"object","additionalProperties":false,"required":["lat","lng"],"properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}}},"radiusKm":{"type":"number","exclusiveMinimum":0,"maximum":100},"centerAddress":{"type":"string","minLength":2,"maxLength":200,"description":"Instead of center: a town, suburb or street in the business's country to measure radiusKm from, e.g. \"Somerset West\" or \"Austin, TX\"."},"centerName":{"type":"string","maxLength":80,"description":"What to call the radius area, e.g. the town."}}},"HoursRequest":{"type":"object","additionalProperties":false,"required":["week"],"properties":{"week":{"$ref":"#/components/schemas/Week"},"resourceIds":{"type":"array","maxItems":20,"items":{"type":"string","maxLength":60},"description":"Only these resources (ids from add_resources). Left out: the whole business."}}},"NewResource":{"type":"object","additionalProperties":false,"required":["kind","name"],"properties":{"id":{"type":"string","pattern":"^[a-z0-9-]{1,60}$","description":"An existing resource's id, to replace it."},"kind":{"type":"string","enum":["VAN","WALKER","SITTER"]},"name":{"type":"string","minLength":1,"maxLength":80},"categories":{"type":"array","items":{"$ref":"#/components/schemas/LineId"},"description":"Defaults to the lines this kind does."},"week":{"$ref":"#/components/schemas/Week","description":"Its working week. Left out: the business's hours from set_operating_hours."},"slotStepMin":{"type":"integer","minimum":5,"maximum":240},"travelBufferMin":{"type":"integer","minimum":0,"maximum":240}}},"ResourcesRequest":{"type":"object","additionalProperties":false,"properties":{"resources":{"type":"array","maxItems":20,"items":{"$ref":"#/components/schemas/NewResource"}},"replace":{"type":"boolean"},"removeIds":{"type":"array","maxItems":20,"items":{"type":"string","maxLength":60}}}},"InviteRequest":{"type":"object","additionalProperties":false,"required":["invites"],"properties":{"invites":{"type":"array","maxItems":30,"items":{"type":"object","additionalProperties":false,"required":["role"],"properties":{"name":{"type":"string","maxLength":80},"email":{"type":"string","maxLength":254},"phone":{"type":"string","maxLength":30},"role":{"type":"string","enum":["manager","crew"],"description":"manager runs the business in the app; crew (groomers, walkers, sitters) see and work the bookings."},"jobTitle":{"type":"string","maxLength":40,"description":"What they do, e.g. Groomer, Walker, Bather."},"resourceIds":{"type":"array","maxItems":20,"items":{"type":"string","maxLength":60},"description":"The vans (or walker/sitter slots) they work, ids from add_resources."}}}},"replace":{"type":"boolean"}}},"PayfastRequest":{"type":"object","additionalProperties":false,"required":["merchantId"],"properties":{"merchantId":{"type":"string","pattern":"^[0-9]{5,12}$","description":"The Payfast merchant id, digits only. Never the merchant key or passphrase."}}},"SubmitRequest":{"type":"object","additionalProperties":false,"properties":{"confirm":{"type":"boolean","description":"true once the person has seen the summary and said yes."}}},"ChecklistItem":{"type":"object","required":["id","label","done","required"],"properties":{"id":{"type":"string","enum":["details","services","area","resources","payfast","payout","staff","listing"]},"label":{"type":"string"},"done":{"type":"boolean"},"required":{"type":"boolean"},"detail":{"type":"string"}}},"BusinessApplication":{"type":"object","required":["applicationId","status","business","checklist","readyToSubmit","next"],"properties":{"applicationId":{"type":"string"},"status":{"$ref":"#/components/schemas/ApplicationStatus"},"business":{"type":"object","additionalProperties":true},"listing":{"type":["object","null"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"town":{"type":"string"}}},"services":{"type":"array","items":{"type":"object","additionalProperties":true}},"areas":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Proposed territories, PENDING until approved."},"overlaps":{"type":"array","items":{"type":"object","properties":{"area":{"type":"string"},"territory":{"type":"string"},"grantedTo":{"type":"string"}}}},"resources":{"type":"array","items":{"type":"object","additionalProperties":true}},"invites":{"type":"array","items":{"type":"object","additionalProperties":true}},"payfast":{"type":["object","null"],"properties":{"merchantId":{"type":"string"},"split":{"type":"boolean"},"status":{"type":"string"}}},"whatsappOptIn":{"type":"boolean"},"plan":{"type":"null","description":"Reserved: NogPets' plan for the business. Not set yet; pricing is by conversation."},"checklist":{"type":"array","items":{"$ref":"#/components/schemas/ChecklistItem"}},"readyToSubmit":{"type":"boolean"},"reviewNote":{"type":"string","description":"Why NogPets asked for changes."},"bizId":{"type":"string","description":"The business, once approved."},"possibleListings":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Directory listings that may be this business: offer to claim one."},"payfastInfo":{"type":"string"},"summary":{"type":"string"},"statusUrl":{"type":["string","null"],"format":"uri","description":"A page the person can open to see the checklist and status."},"welcomeUrl":{"type":"string","format":"uri","description":"What NogPets offers businesses, for the person to read."},"next":{"type":"string","description":"What to do now."}}}}}}