FairCar Developer API
One documented REST surface behind the FairCar iOS and Android apps. Every endpoint runs the same pricing, host rules and permissions as faircar.app, so a native client can never drift from the website.
Getting started
1. Base URL
https://faircar.app/api/public/v1
Responses are JSON. Amounts are USD; fields ending in _cents are integers in cents. Trip dates are YYYY-MM-DD; timestamps are ISO-8601 UTC.
2a. Get a token from an API key
POST https://faircar.app/api/public/v1/auth/token
Content-Type: application/json
{ "api_key": "fc_live_…" }
→ { "access_token": "eyJ…", "refresh_token": "…", "token_type": "bearer", "expires_in": 3600 }Any signed-in FairCar member can create a personal key under Account → API keys. The key is shown once, acts only on that member's own data, and can be revoked at any time. Exchange it for an access token, then send Authorization: Bearer <access_token> on every authenticated call. Keep keys server-side; never ship one inside a mobile or browser app.
2b. Or sign each user in directly
POST https://npsimakbiyqxrmwgzhjn.supabase.co/auth/v1/token?grant_type=password
apikey: sb_publishable_9k2hA5eNNChKf0xWtX6k7g_edcPMOE9
Content-Type: application/json
{ "email": "guest@example.com", "password": "…" }
→ { "access_token": "eyJ…", "refresh_token": "…", "expires_in": 3600 }This is the right path for consumer apps: use an official Supabase SDK (email + password, Google, Apple or magic link) with the publishable key above, then send the returned access token as Authorization: Bearer …. Tokens last one hour — let the SDK refresh them, or call /auth/token again with your API key.
3. Call the API
curl "https://faircar.app/api/public/v1/vehicles?location=Nashville&start_date=2026-10-04&end_date=2026-10-08&limit=20"
curl -H "Authorization: Bearer $ACCESS_TOKEN" "https://faircar.app/api/public/v1/me"
curl -X POST "https://faircar.app/api/public/v1/bookings" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"vehicle_id":"…","start_date":"2026-10-04","end_date":"2026-10-08",
"return_url":"yourapp://checkout/return","environment":"live"}'Endpoints
Discovery
No token needed. Everything a browsing screen needs before sign-in.
/vehiclesSearch active listings. Filters: start_date, end_date, location, make, model, type, min_seats, min_daily_rate, max_daily_rate, instant_book, sort, limit, offset.
/vehicles/{vehicle_id}Full listing detail including photos, features, fees, rules and pickup locations.
/vehicles/{vehicle_id}/availabilityDates blocked by the host or already booked, from today forward.
/vehicles/{vehicle_id}/reviewsReviews and the combined rating shown on the web listing.
/vehicles/{vehicle_id}/quoteAuthoritative trip price: subtotal, discount, 10% guest fee, tax, total, all-in per day.
/citiesSupported city slugs, names, states.
/airportsSupported airports with IATA codes.
/profiles/{user_id}Public profile and badges for a host or guest.
Account
The signed-in user. Requires a Supabase access token.
/auth/tokenExchange a personal API key (body: api_key, or header X-API-Key) for a short-lived access token.
/meProfile, roles, host/admin flags, verification state.token required
/meUpdate display name, bio, city, region, country, languages.token required
/me/favoritesSaved cars.token required
/me/favoritesToggle a saved car (body: vehicle_id).token required
/me/tripsTrips as a guest, optional ?status= filter.token required
Bookings & payment
Quote → create → pay with Stripe → poll for confirmation.
/bookingsRuns every host rule and gate, holds the dates for 10 minutes, returns a Stripe Checkout client secret.token required
/bookingsMy bookings.token required
/bookings/{booking_id}Booking detail for the guest or the host, with pickup/return details once authorised.token required
/bookings/{booking_id}/cancellation-quoteRefund preview under the listing's cancellation policy.token required
/bookings/{booking_id}/cancelCancel and refund (guest or host).token required
/bookings/{booking_id}/release-holdFree the dates immediately when checkout is abandoned.token required
Messaging
Guest ↔ host conversations tied to a booking.
/threads?role=guest|hostInbox with participant profiles and unread counts.token required
/threads/{thread_id}Thread with all messages; marks it read.token required
/threads/{thread_id}/messagesMessages only, oldest first.token required
/threads/{thread_id}/messagesSend a message (body: body).token required
Reviews
Post-trip ratings in both directions.
/reviewsCompleted trips still awaiting my review.token required
/reviewsSubmit a review (booking_id, rating 1–5, comment, tags).token required
Host tools
Host-side screens for the native app.
/host/listingsAll of my listings, including paused and unpublished.token required
/host/bookingsBookings across my cars, optional ?status= filter.token required
/host/vehicles/{vehicle_id}/calendarBlocked days plus booking spans with guest metadata.token required
/host/vehicles/{vehicle_id}/calendarBlock or unblock dates (blocked_dates, block).token required
Booking and payment flow
- 1. Price the trip with
POST /vehicles/{id}/quoteand show the exact breakdown. - 2. Call
POST /bookings. Host rules (minimum trip length, advance notice, age and ID gates) are enforced server-side; the dates are held for 10 minutes and a Stripe Checkout client secret comes back. - 3. Complete payment with the Stripe mobile SDK or a web view, returning to the
return_urldeep link you supplied. - 4. Poll
GET /bookings/{id}until status isconfirmed— our Stripe webhook confirms the trip, never the client. - 5. If the guest backs out, call
POST /bookings/{id}/release-holdto free the dates immediately.
Errors
{ "error": { "code": "unauthorized", "message": "A valid Supabase access token is required." } }unauthorized 401 · forbidden 403 · not_found 404 · conflict 409 · validation_failed 422 · bad_request 400. CORS is open for all origins, and every path accepts OPTIONS preflight.
