Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Muhammadbugaje/trustride/llms.txt

Use this file to discover all available pages before exploring further.

The TrustRide Ambassador Program enables trusted platform users to act as booking agents for people who cannot book online themselves. Ambassadors walk into transport terminals, take seat orders from travellers in person, and confirm the bookings directly in TrustRide. They earn a percentage commission on every seat they book and help drivers fill their vehicles faster.
Ambassadors are especially valuable in areas with low smartphone penetration across Nigeria. A single ambassador operating at a motor park in Kaduna, Kano, or Aba can book dozens of seats per week for travellers who only have feature phones — bridging the gap between offline demand and TrustRide’s digital supply.

What Is an Ambassador?

An ambassador is a verified TrustRide user who has been approved to book seats on behalf of third parties. When an ambassador creates a booking, the booked_by_ambassador field on the Booking record is set to the ambassador’s user ID, and the actual traveller’s details (rider_name, rider_phone, rider_email) are stored separately on the booking. Key characteristics:
  • Ambassadors are not a separate user role — they hold role=rider or role=driver and gain ambassador capability as an overlay.
  • Before booking any driver’s trip, an ambassador must request and receive explicit per-trip approval from the driver.
  • Ambassadors earn ambassador_commission_rate (default 5%) on each booking they facilitate.

Applying to Become an Ambassador

Any registered TrustRide user can apply to become an ambassador. POST /apply-ambassador/ — submits an AmbassadorApplication record with the following fields:
FieldDescription
full_nameApplicant’s full name
phoneContact phone number
emailContact email
locationCity or area where the ambassador will operate
reasonMotivation statement reviewed by admin
referral_sourceOptional — how they heard about the program
class AmbassadorApplication(models.Model):
    STATUS_CHOICES = [
        ('pending',  'Pending Review'),
        ('approved', 'Approved'),
        ('rejected', 'Rejected'),
    ]

    user             = models.ForeignKey(User, related_name='ambassador_applications')
    full_name        = models.CharField(max_length=100)
    phone            = models.CharField(max_length=20)
    email            = models.EmailField()
    location         = models.CharField(max_length=200)
    reason           = models.TextField()
    referral_source  = models.CharField(max_length=100, blank=True)
    status           = models.CharField(choices=STATUS_CHOICES, default='pending')
    reviewed_by      = models.ForeignKey(User, null=True, related_name='reviewed_applications')
    reviewed_at      = models.DateTimeField(null=True, blank=True)
    admin_notes      = models.TextField(blank=True)
If a user already has a pending application, submitting a second one redirects them to their profile with a warning. Only one active pending application is allowed per user at a time.

Ambassador Approval Flow

1

Application Submitted

User posts to /apply-ambassador/. An AmbassadorApplication record is created with status=pending.
2

Admin Reviews Application

Admin reviews the application in the Django admin panel, checks the applicant’s location, reputation, and reason statement.
3

Admin Approves

Admin sets AmbassadorApplication.status=approved and updates the user’s User record:
  • is_ambassador = True
  • ambassador_status = 'active'
  • ambassador_approved_at = now()
  • ambassador_approved_by = <admin user>
  • ambassador_commission_rate is set (defaults to 5.0%)
4

Ambassador Access Unlocked

The user can now access /ambassador/dashboard/ and request trip approvals from drivers.

Ambassador Status States

The ambassador_status field on User controls an ambassador’s operational access:
active — Full ambassador access. Can request trip approvals, book seats, and view commissions.paused — Admin has temporarily suspended ambassador activity. The ambassador can still log in and view their dashboard but cannot book new seats. A warning banner is displayed.revoked — Permanently revoked by admin. Attempting to access the ambassador dashboard redirects the user to the homepage with an error message. is_ambassador remains True as an audit trail, but all booking capabilities are blocked.

Ambassador Dashboard

GET /ambassador/dashboard/ — requires is_ambassador=True. Users with ambassador_status=revoked are immediately redirected. The dashboard surfaces:
  • Approved tripsAmbassadorTripApproval records where is_approved=True, grouped by departure date.
  • Pending trip requests — approvals where is_approved=False and approved_at is NULL (never approved).
  • Paused approvals — approvals where is_approved=False but approved_at is set (previously approved, then paused by driver).
  • Active bookings — upcoming bookings made by the ambassador where trip.departure_date >= today.
  • All published trips — a list of bookable trips the ambassador has not yet requested access to.
  • Status counts — badge counts for approved, pending, and paused approvals.

Requesting Trip Approval

Before an ambassador can book seats on a driver’s trip, they must request explicit approval for that specific trip. POST /ambassador/request-approval/<uuid>/ — creates an AmbassadorTripApproval record:
class AmbassadorTripApproval(models.Model):
    ambassador  = models.ForeignKey(User, related_name='trip_approvals')
    trip        = models.ForeignKey(Trip, related_name='ambassador_approvals')
    driver      = models.ForeignKey(User, related_name='granted_approvals')
    is_approved = models.BooleanField(default=True)    # set to False explicitly when a request is created
    approved_at = models.DateTimeField(null=True, blank=True)
    revoked_at  = models.DateTimeField(null=True, blank=True)
    revoked_by  = models.ForeignKey(User, null=True, blank=True)

    class Meta:
        unique_together = ['ambassador', 'trip']
When the request is created, the driver receives an in-app notification directing them to /driver/ambassador-requests/. An ambassador cannot request approval on their own trip, and submitting a duplicate request (for a trip they already requested) is gracefully ignored with an informational message.

Driver Approves the Ambassador

GET/POST /driver/ambassador-requests/ — the driver sees all pending AmbassadorTripApproval records where is_approved=False. Posting action=approve with a request_id:
  • Sets is_approved=True
  • Records approved_at=now()
Posting action=reject:
  • Deletes the AmbassadorTripApproval record entirely
The driver can also manage already-approved ambassadors at GET/POST /driver/manage-ambassadors/, which groups all approvals by trip and allows pause, resume, or remove actions per ambassador.

Booking on Behalf of Riders

Once approved for a trip, an ambassador books seats at the booking form page. GET /ambassador/book-seat/<uuid>/ — renders a seat map identical to the one riders see.
POST /ambassador/book-seat/<uuid>/ — creates bookings with the following key differences from a standard rider booking:
FieldValue
booked_by_ambassadorSet to the ambassador’s User ID
riderSet to the ambassador (temporary placeholder)
rider_nameThird-party passenger’s full name (required)
rider_phoneThird-party passenger’s phone number (required)
rider_emailThird-party passenger’s email (optional)
statusCreated as confirmed immediately — no payment verification step
# Ambassador booking creation (simplified)
Booking.objects.create(
    trip=trip,
    seat_id=seat_id,
    rider=request.user,             # ambassador as placeholder
    booked_by_ambassador=request.user,
    rider_name=rider_name,          # actual traveller
    rider_phone=rider_phone,
    rider_email=rider_email,
    status='confirmed',             # immediate confirmation
    price=trip.price_per_seat,
)
Ambassador bookings bypass the payment receipt workflow and are created as confirmed immediately. Payment collection from the passenger is the ambassador’s responsibility and is handled off-platform (in person at the terminal).

Managing Ambassador Bookings

  • GET /ambassador/my-bookings/ — lists all bookings created by the ambassador. Supports filter query parameter: upcoming (default), past, or all.
  • POST /ambassador/cancel-booking/<uuid>/ — cancels a confirmed booking, releases the seat, and decrements available_seats. Only future-trip bookings can be cancelled.

Trip Approvals List

GET /ambassador/trip-approvals/ — shows the full history of trip approval requests for the ambassador. Displays a table with:
  • Trip origin and destination
  • Driver name
  • Approval status (is_approved=True / pending)
  • Approved timestamp
Badge counts for approved_count and pending_count are displayed in the page header. From this page, ambassadors can cancel a pending request (POST /ambassador/cancel-request/<id>/) or leave an already-approved trip (POST /ambassador/leave-trip/<id>/).

Commission

The ambassador_commission_rate field stores the ambassador’s commission as a percentage:
ambassador_commission_rate = models.DecimalField(
    max_digits=5,
    decimal_places=2,
    default=5.0,
    help_text='Commission rate in % (e.g., 5.0 = 5%)'
)
Commission tracking and payout are managed by the TrustRide admin team. The rate is set per ambassador at the time of approval and can be adjusted by admin at any time. A commission of 5% on a ₦5,000 seat booking, for example, yields ₦250 per seat.
Commission rates, payout schedules, and ambassador-specific notes are stored in ambassador_notes on the User model — visible only to admin. Ambassadors can contact the support team to query their commission balance.

Build docs developers (and LLMs) love