Bubbly Maps API
API Reference

Waypoints API

Complete reference for the Waypoints API endpoints

Waypoints API

The Waypoints API allows you to manage water fountain locations (waypoints). You can list, create, update, and search for waypoints.

Endpoints

GET /api/waypoints

Get all waypoints in the system.

Authentication: Not required

Response:

{
  "license": "CC BY-NC 4.0",
  "author": "Linus Kang",
  "waypoints": [
    {
      "id": 1,
      "name": "Central Park Fountain",
      "latitude": 40.7829,
      "longitude": -73.9654,
      "description": "Beautiful fountain near the lake",
      "amenities": ["accessible", "pet-friendly"],
      "image": "https://example.com/image.jpg",
      "maintainer": "NYC Parks",
      "region": "New York",
      "approved": true,
      "verified": true,
      "addedByUserId": "user123",
      "createdAt": "2024-01-15T10:30:00Z",
      "updatedAt": "2024-01-15T10:30:00Z"
    }
  ]
}

POST /api/waypoints

Create a new waypoint.

Authentication: Required (Session or API Token)

Request Body:

{
  "name": "Example Fountain",
  "latitude": 40.7128,
  "longitude": -74.0060,
  "description": "A convenient water fountain",
  "amenities": ["accessible"],
  "image": "https://example.com/fountain.jpg",
  "maintainer": "City Parks",
  "region": "Manhattan"
}

Required Fields:

  • name (string) - Name of the waypoint
  • latitude (number) - Latitude coordinate
  • longitude (number) - Longitude coordinate

Optional Fields:

  • description (string) - Description of the waypoint
  • amenities (array) - Array of amenity strings
  • image (string) - URL to waypoint image
  • maintainer (string) - Entity responsible for maintenance
  • region (string) - Geographic region

API Token Only Fields:

  • approved (boolean) - Whether the waypoint is approved
  • verified (boolean) - Whether the waypoint is verified
  • addedByUserId (string) - User ID of the creator

XP Requirements:

Regular users need sufficient XP (experience points) to create waypoints. API tokens bypass this requirement.

Example Request:

curl -X POST https://bubblymaps.org/api/waypoints \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d '{
    "name": "Bryant Park Fountain",
    "latitude": 40.7536,
    "longitude": -73.9832,
    "description": "Modern fountain in the park",
    "amenities": ["accessible", "filtered"],
    "region": "Manhattan"
  }'

Response (201 Created):

{
  "id": 42,
  "name": "Bryant Park Fountain",
  "latitude": 40.7536,
  "longitude": -73.9832,
  "description": "Modern fountain in the park",
  "amenities": ["accessible", "filtered"],
  "region": "Manhattan",
  "approved": false,
  "verified": false,
  "addedByUserId": "api",
  "createdAt": "2024-01-20T15:45:00Z",
  "updatedAt": "2024-01-20T15:45:00Z"
}

Error Responses:

  • 401 Unauthorized - Missing or invalid authentication
  • 403 Forbidden - Insufficient XP to create waypoint
  • 400 Bad Request - Missing required fields or invalid data

GET /api/waypoints/[id]

Get a specific waypoint by ID, including its change logs.

Authentication: Not required

URL Parameters:

  • id (number) - Waypoint ID

Example Request:

curl https://bubblymaps.org/api/waypoints/42

Response:

{
  "waypoint": {
    "id": 42,
    "name": "Bryant Park Fountain",
    "latitude": 40.7536,
    "longitude": -73.9832,
    "description": "Modern fountain in the park",
    "amenities": ["accessible", "filtered"],
    "region": "Manhattan",
    "approved": true,
    "verified": true,
    "addedByUserId": "user456",
    "createdAt": "2024-01-20T15:45:00Z",
    "updatedAt": "2024-01-21T10:00:00Z"
  },
  "logs": [
    {
      "id": 1,
      "bubblerId": 42,
      "userId": "user456",
      "action": "created",
      "timestamp": "2024-01-20T15:45:00Z"
    },
    {
      "id": 2,
      "bubblerId": 42,
      "userId": "moderator123",
      "action": "approved",
      "timestamp": "2024-01-21T10:00:00Z"
    }
  ]
}

Error Responses:

  • 404 Not Found - Waypoint does not exist
  • 400 Bad Request - Invalid waypoint ID

PATCH /api/waypoints/[id]

Update an existing waypoint.

Authentication: Required (Session or API Token)

URL Parameters:

  • id (number) - Waypoint ID

Request Body:

Any combination of the fields from POST /api/waypoints. Only provided fields will be updated.

Example Request:

curl -X PATCH https://bubblymaps.org/api/waypoints/42 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d '{
    "description": "Updated description with more details",
    "verified": true
  }'

XP Requirements:

Regular users need sufficient XP to edit waypoints. API tokens bypass this requirement.

Response:

{
  "id": 42,
  "name": "Bryant Park Fountain",
  "latitude": 40.7536,
  "longitude": -73.9832,
  "description": "Updated description with more details",
  "amenities": ["accessible", "filtered"],
  "region": "Manhattan",
  "approved": true,
  "verified": true,
  "addedByUserId": "user456",
  "createdAt": "2024-01-20T15:45:00Z",
  "updatedAt": "2024-01-22T12:30:00Z"
}

Error Responses:

  • 401 Unauthorized - Missing or invalid authentication
  • 403 Forbidden - Insufficient XP to edit waypoint
  • 400 Bad Request - Invalid data
  • 404 Not Found - Waypoint does not exist

GET /api/waypoints/search

Search for waypoints by name or other criteria.

Authentication: Not required

Query Parameters:

  • q (string, required) - Search query string

Example Request:

curl "https://bubblymaps.org/api/waypoints/search?q=park"

Response:

{
  "waypoints": [
    {
      "id": 42,
      "name": "Bryant Park Fountain",
      "latitude": 40.7536,
      "longitude": -73.9832,
      "description": "Modern fountain in the park",
      "region": "Manhattan"
    },
    {
      "id": 43,
      "name": "Central Park North Fountain",
      "latitude": 40.7967,
      "longitude": -73.9519,
      "description": "Fountain in Central Park",
      "region": "Manhattan"
    }
  ]
}

Error Responses:

  • 500 Internal Server Error - Search failed

Data Model

Waypoint Object

FieldTypeDescription
idnumberUnique identifier
namestringName of the waypoint
latitudenumberLatitude coordinate
longitudenumberLongitude coordinate
descriptionstringDescription of the waypoint
amenitiesstring[]Array of amenities
imagestringURL to waypoint image
maintainerstringMaintenance entity
regionstringGeographic region
approvedbooleanApproval status
verifiedbooleanVerification status
addedByUserIdstringCreator user ID
createdAtstringCreation timestamp (ISO 8601)
updatedAtstringLast update timestamp (ISO 8601)

Usage Examples

JavaScript/Fetch - Get All Waypoints

async function getAllWaypoints() {
  const response = await fetch('https://bubblymaps.org/api/waypoints');
  
  if (!response.ok) {
    throw new Error('Failed to fetch waypoints');
  }
  
  const data = await response.json();
  return data.waypoints;
}

// Usage
getAllWaypoints()
  .then(waypoints => {
    console.log(`Found ${waypoints.length} waypoints`);
    waypoints.forEach(wp => {
      console.log(`${wp.name} at (${wp.latitude}, ${wp.longitude})`);
    });
  })
  .catch(error => console.error('Error:', error));

JavaScript/Fetch - Create Waypoint with Error Handling

async function createWaypoint(waypointData) {
  try {
    const response = await fetch('https://bubblymaps.org/api/waypoints', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer YOUR_API_TOKEN'
      },
      body: JSON.stringify(waypointData)
    });
    
    if (response.status === 403) {
      throw new Error('Insufficient XP to create waypoint');
    }
    
    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.message || 'Failed to create waypoint');
    }
    
    return await response.json();
  } catch (error) {
    console.error('Error creating waypoint:', error);
    throw error;
  }
}

// Usage
createWaypoint({
  name: 'New Park Fountain',
  latitude: 40.7589,
  longitude: -73.9851,
  description: 'Clean water fountain in the park',
  amenities: ['accessible', 'cold-water'],
  region: 'Manhattan'
})
  .then(data => console.log('Created waypoint:', data))
  .catch(error => console.error('Failed:', error));

Python - Search and Filter Waypoints

import requests

def search_waypoints_by_region(query, region=None):
    """Search for waypoints and optionally filter by region"""
    url = f"https://bubblymaps.org/api/waypoints/search?q={query}"
    response = requests.get(url)
    
    if response.status_code != 200:
        raise Exception(f"Search failed: {response.status_code}")
    
    waypoints = response.json()['waypoints']
    
    # Client-side filtering by region if needed
    if region:
        waypoints = [wp for wp in waypoints if wp.get('region') == region]
    
    return waypoints

# Usage
results = search_waypoints_by_region('fountain', region='Manhattan')
print(f"Found {len(results)} fountains in Manhattan")
for wp in results:
    print(f"- {wp['name']}: {wp.get('description', 'No description')}")

Python - Update Waypoint

import requests

def update_waypoint(waypoint_id, updates, api_token):
    """Update a waypoint with new information"""
    url = f"https://bubblymaps.org/api/waypoints/{waypoint_id}"
    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {api_token}'
    }
    
    response = requests.patch(url, json=updates, headers=headers)
    
    if response.status_code == 404:
        raise Exception(f"Waypoint {waypoint_id} not found")
    elif response.status_code == 403:
        raise Exception("Insufficient XP to edit waypoint")
    elif response.status_code != 200:
        raise Exception(f"Update failed: {response.status_code}")
    
    return response.json()

# Usage
try:
    updated = update_waypoint(
        waypoint_id=42,
        updates={
            'description': 'Recently renovated fountain with cold water',
            'amenities': ['accessible', 'cold-water', 'bottle-filler']
        },
        api_token='your_api_token_here'
    )
    print(f"Updated waypoint: {updated['name']}")
except Exception as e:
    print(f"Error: {e}")

Use Cases

The Waypoints API is useful for:

  • Mobile Apps - Display water fountains on a map
  • Navigation - Help users find the nearest fountain
  • Data Collection - Crowdsource fountain locations
  • Verification - Allow community verification of data
  • Integration - Sync fountain data with other services
  • Analytics - Track fountain distribution and usage

Best Practices

Creating Waypoints

  1. Verify coordinates - Ensure latitude and longitude are correct
  2. Add descriptions - Help users know what to expect
  3. Include amenities - Make fountains easier to find for specific needs
  4. Add photos - Visual confirmation helps users identify fountains
  5. Specify region - Helps with geographic filtering

Updating Waypoints

  1. Only update what changed - Send only modified fields
  2. Check verification status - Verified waypoints may need moderator review
  3. Add detailed descriptions - More information helps the community
  4. Keep photos current - Update images if the fountain changes

Searching

  1. Use specific terms - Better search results with specific queries
  2. Cache results - Don't repeatedly search for the same terms
  3. Handle empty results - Always check if results array is empty

Rate Limiting

While the API currently doesn't enforce strict rate limits, please be respectful:

  • Cache responses when possible
  • Batch requests instead of making many individual calls
  • Use search instead of fetching all waypoints repeatedly
  • Maximum 100 requests per minute recommended

Error Response Format

All error responses follow this format:

{
  "error": "Error message description",
  "code": "ERROR_CODE",
  "details": {
    "field": "Additional context"
  }
}

Common error codes:

  • INSUFFICIENT_XP - User doesn't have enough XP
  • INVALID_COORDINATES - Coordinates out of valid range
  • INVALID_INPUT - Missing or malformed data
  • NOT_FOUND - Resource doesn't exist
  • UNAUTHORIZED - Authentication required or invalid

On this page