API Reference

Complete REST API documentation for BrewHoard's versioned API endpoints.

BrewHoard provides a comprehensive REST API for all operations. The API is versioned and follows RESTful conventions.

Base URL

Text
Production: https://your-domain.com/api/v1
Development: http://localhost:5173/api/v1

Authentication

The API supports two authentication methods:

Session Cookie (Browser)

For browser-based requests, authentication uses HTTP-only session cookies:

JavaScript
// Login creates a session cookie
const response = await fetch('/api/v1/auth/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email, password }),
  credentials: 'include' // Important for cookies
});

API Key (Programmatic)

For server-to-server or CLI access, use API keys:

Bash
curl -X GET "https://api.brewhoard.com/api/v1/collection" 
  -H "Authorization: Bearer bv_live_xxxxxxxxxxxxxxxxxxxx"

API keys are prefixed with bv_live_ (production) or bv_test_ (development).

Response Format

All responses follow a consistent structure:

Success Response

JSON
{
  "success": true,
  "data": {
    // Response data here
  },
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 150
  }
}

Error Response

JSON
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid email format",
    "details": {
      "field": "email",
      "constraint": "email"
    }
  }
}

Common Error Codes

CodeHTTP StatusDescription
UNAUTHORIZED401Missing or invalid authentication
FORBIDDEN403Insufficient permissions
NOT_FOUND404Resource not found
VALIDATION_ERROR400Invalid request data
RATE_LIMITED429Too many requests
SERVER_ERROR500Internal server error

Rate Limiting

API requests are rate-limited per user/IP:

Endpoint TypeLimit
Authentication10 requests/minute
Read operations100 requests/minute
Write operations30 requests/minute
File uploads10 requests/minute

Rate limit headers are included in responses:

Text
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1699876543

Authentication Endpoints

POST /auth/register

Create a new user account.

Request:

JSON
{
  "email": "user@example.com",
  "password": "securepassword123",
  "displayName": "Beer Lover"
}

Response:

JSON
{
  "success": true,
  "data": {
    "user": {
      "id": "uuid",
      "email": "user@example.com",
      "displayName": "Beer Lover",
      "createdAt": "2024-01-15T10:30:00Z"
    }
  }
}

POST /auth/login

Authenticate and create a session.

Request:

JSON
{
  "email": "user@example.com",
  "password": "securepassword123"
}

Response:

JSON
{
  "success": true,
  "data": {
    "user": {
      "id": "uuid",
      "email": "user@example.com",
      "displayName": "Beer Lover"
    },
    "expiresAt": "2024-01-22T10:30:00Z"
  }
}

POST /auth/api-keys

Create a new API key.

Request:

JSON
{
  "name": "CLI Access",
  "scopes": ["collection:read", "collection:write"],
  "expiresAt": "2025-01-15T00:00:00Z"
}

Response:

JSON
{
  "success": true,
  "data": {
    "id": "uuid",
    "name": "CLI Access",
    "key": "bv_live_xxxxxxxxxxxxxxxxxxxx",
    "keyPrefix": "bv_live_",
    "scopes": ["collection:read", "collection:write"],
    "expiresAt": "2025-01-15T00:00:00Z"
  }
}

Note: The full API key is only returned once. Store it securely.


Beer Endpoints

GET /beers

Search and list beers.

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | q | string | Search query (name, brewery) | | style | string | Filter by beer style | | minAbv | number | Minimum ABV | | maxAbv | number | Maximum ABV | | breweryId | uuid | Filter by brewery | | page | number | Page number (default: 1) | | limit | number | Results per page (default: 20, max: 100) |

Example:

Bash
curl "/api/v1/beers?q=IPA&minAbv=6&limit=10"

Response:

JSON
{
  "success": true,
  "data": {
    "beers": [
      {
        "id": "uuid",
        "name": "Hop Heaven IPA",
        "style": "IPA",
        "abv": 6.5,
        "ibu": 65,
        "brewery": {
          "id": "uuid",
          "name": "Craft Brewery Co"
        },
        "avgRating": 4.2,
        "ratingCount": 156
      }
    ]
  },
  "meta": {
    "page": 1,
    "limit": 10,
    "total": 45
  }
}

GET /beers/:id

Get detailed beer information.

Response:

JSON
{
  "success": true,
  "data": {
    "id": "uuid",
    "name": "Hop Heaven IPA",
    "style": "IPA",
    "substyle": "West Coast IPA",
    "abv": 6.5,
    "ibu": 65,
    "description": "A bold, hop-forward IPA with citrus and pine notes.",
    "imageUrl": "https://cdn.brewhoard.com/beers/hop-heaven.jpg",
    "brewery": {
      "id": "uuid",
      "name": "Craft Brewery Co",
      "country": "US",
      "city": "Portland"
    },
    "stats": {
      "avgRating": 4.2,
      "ratingCount": 156,
      "inCollections": 89
    }
  }
}

GET /beers/styles

Get available beer styles.

Response:

JSON
{
  "success": true,
  "data": {
    "styles": [
      { "name": "IPA", "count": 1250 },
      { "name": "Stout", "count": 890 },
      { "name": "Lager", "count": 756 }
    ]
  }
}

Collection Endpoints

GET /collection

Get the authenticated user’s collection.

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | style | string | Filter by beer style | | forTrade | boolean | Only show items marked for trade | | sort | string | Sort field: name, addedAt, quantity | | order | string | Sort order: asc, desc |

Response:

JSON
{
  "success": true,
  "data": {
    "items": [
      {
        "id": "uuid",
        "beer": {
          "id": "uuid",
          "name": "Hop Heaven IPA",
          "style": "IPA",
          "brewery": { "name": "Craft Brewery Co" }
        },
        "quantity": 6,
        "containerType": "bottle",
        "containerSizeMl": 330,
        "storageLocation": "Beer Fridge",
        "isForTrade": false,
        "acquisitions": [
          {
            "id": "uuid",
            "quantity": 6,
            "purchasePrice": 12.99,
            "purchaseCurrency": "USD",
            "purchaseDate": "2024-01-10",
            "purchaseLocation": "Local Brewery"
          }
        ],
        "createdAt": "2024-01-10T15:30:00Z"
      }
    ],
    "stats": {
      "uniqueBeers": 45,
      "totalBottles": 128,
      "totalValue": 892.50
    }
  }
}

POST /collection

Add a beer to the collection.

Request:

JSON
{
  "beerId": "uuid",
  "quantity": 6,
  "containerType": "bottle",
  "containerSizeMl": 330,
  "storageLocation": "Beer Fridge",
  "notes": "Anniversary edition",
  "acquisition": {
    "purchasePrice": 12.99,
    "purchaseCurrency": "USD",
    "purchaseDate": "2024-01-10",
    "purchaseLocation": "Local Brewery"
  }
}

Response:

JSON
{
  "success": true,
  "data": {
    "id": "uuid",
    "beerId": "uuid",
    "quantity": 6,
    "createdAt": "2024-01-10T15:30:00Z"
  }
}

PATCH /collection/:id

Update a collection item.

Request:

JSON
{
  "quantity": 5,
  "storageLocation": "Cellar",
  "isForTrade": true
}

DELETE /collection/:id

Remove an item from the collection.

POST /collection/consume

Record consumption of a beer.

Request:

JSON
{
  "collectionItemId": "uuid",
  "quantity": 1,
  "notes": "Shared with friends",
  "rating": {
    "overall": 4.5,
    "reviewText": "Excellent hoppy character"
  }
}

Marketplace Endpoints

GET /marketplace/listings

Browse active marketplace listings.

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | q | string | Search query | | style | string | Filter by beer style | | minPrice | number | Minimum price | | maxPrice | number | Maximum price | | shipsTo | string | Country code for shipping | | sort | string | price, newest, popular |

Response:

JSON
{
  "success": true,
  "data": {
    "listings": [
      {
        "id": "uuid",
        "title": "Vintage 2020 Imperial Stout",
        "beer": {
          "id": "uuid",
          "name": "Imperial Stout Reserve",
          "style": "Imperial Stout"
        },
        "seller": {
          "id": "uuid",
          "displayName": "BeerCollector42",
          "rating": 4.8,
          "salesCount": 23
        },
        "quantity": 2,
        "price": 45.00,
        "currency": "USD",
        "shippingCost": 12.00,
        "condition": "aged",
        "photos": ["https://cdn.brewhoard.com/listings/..."],
        "createdAt": "2024-01-12T09:00:00Z"
      }
    ]
  }
}

POST /marketplace/listings

Create a new listing.

Request:

JSON
{
  "collectionItemId": "uuid",
  "title": "Rare 2018 Barrel-Aged Stout",
  "description": "Perfectly cellared for 6 years",
  "quantity": 1,
  "price": 75.00,
  "currency": "USD",
  "shippingCost": 15.00,
  "shipsTo": ["US", "CA", "GB"],
  "condition": "vintage",
  "photos": ["data:image/jpeg;base64,..."]
}

POST /marketplace/transactions

Initiate a purchase.

Request:

JSON
{
  "listingId": "uuid",
  "quantity": 1,
  "shippingAddress": {
    "name": "John Doe",
    "street": "123 Main St",
    "city": "Portland",
    "state": "OR",
    "postalCode": "97201",
    "country": "US"
  }
}

Response:

JSON
{
  "success": true,
  "data": {
    "transactionId": "uuid",
    "stripeClientSecret": "pi_xxxxx_secret_xxxxx",
    "amount": 90.00,
    "currency": "USD"
  }
}

Rating Endpoints

GET /ratings

Get ratings for a beer.

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | beerId | uuid | Required: Beer ID | | sort | string | newest, highest, helpful |

POST /ratings

Submit a rating.

Request:

JSON
{
  "beerId": "uuid",
  "overallRating": 4.5,
  "aromaRating": 4.0,
  "appearanceRating": 4.5,
  "tasteRating": 5.0,
  "mouthfeelRating": 4.0,
  "reviewText": "Exceptional hop character with a clean finish.",
  "tastingNotes": {
    "flavors": ["citrus", "pine", "tropical"],
    "aromas": ["grapefruit", "floral"],
    "mouthfeel": ["crisp", "medium-bodied"]
  },
  "servingType": "draft",
  "isPublic": true
}

Scanner Endpoints

POST /scanner/recognize

Identify a beer from an image.

Request:

Text
Content-Type: multipart/form-data

image: <binary image data>

Response:

JSON
{
  "success": true,
  "data": {
    "matches": [
      {
        "beer": {
          "id": "uuid",
          "name": "Hop Heaven IPA",
          "brewery": { "name": "Craft Brewery Co" }
        },
        "confidence": 0.92,
        "matchedOn": ["label", "logo"]
      },
      {
        "beer": {
          "id": "uuid",
          "name": "Hop Paradise IPA"
        },
        "confidence": 0.75
      }
    ],
    "extractedText": ["Hop Heaven", "IPA", "6.5% ABV"]
  }
}

POST /scanner/scan

Scan a barcode.

Request:

JSON
{
  "barcode": "5901234123457",
  "type": "EAN13"
}

Export Endpoints

POST /export

Export collection data.

Request:

JSON
{
  "format": "csv",
  "includeHistory": true,
  "includeRatings": true,
  "dateRange": {
    "start": "2023-01-01",
    "end": "2024-01-15"
  }
}

Response:

JSON
{
  "success": true,
  "data": {
    "downloadUrl": "https://cdn.brewhoard.com/exports/export-xxxxx.csv",
    "expiresAt": "2024-01-16T10:30:00Z",
    "recordCount": 145
  }
}

Webhooks

Configure webhooks to receive real-time notifications:

Available Events

EventDescription
transaction.createdNew purchase initiated
transaction.completedPurchase completed
listing.soldYour listing was purchased
rating.receivedSomeone rated your transaction

Webhook Payload

JSON
{
  "event": "transaction.completed",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "transactionId": "uuid",
    "buyerId": "uuid",
    "sellerId": "uuid",
    "amount": 90.00
  }
}

SDK Examples

JavaScript/TypeScript

JavaScript
// Using fetch
async function getCollection() {
  const response = await fetch('/api/v1/collection', {
    headers: {
      'Authorization': `Bearer ${apiKey}`
    }
  });
  return response.json();
}

// Using the BrewHoard SDK (coming soon)
import { BrewHoard } from '@brewhoard/sdk';

const client = new BrewHoard({ apiKey: 'bv_live_xxx' });
const collection = await client.collection.list();

cURL

Bash
# Get collection
curl -X GET "https://api.brewhoard.com/api/v1/collection" 
  -H "Authorization: Bearer bv_live_xxx"

# Add to collection
curl -X POST "https://api.brewhoard.com/api/v1/collection" 
  -H "Authorization: Bearer bv_live_xxx" 
  -H "Content-Type: application/json" 
  -d '{"beerId": "uuid", "quantity": 6}'

Next Steps