# Get Available Offers
> Source: /api-reference/members/loyalty/get-offers
> Get offers available to the member based on their tier, property, and eligibility
> Endpoint: GET /members/me/loyalty/offers

## Overview [#overview]

Returns offers available to the authenticated member based on their tier level, current location or property context, and eligibility criteria. Offers are point-based purchases for discounts, upgrades, and exclusive experiences.

## Authentication [#authentication]

Requires a valid Clerk JWT token in the Authorization header.

## Query Parameters [#query-parameters]

<ParamField query="propertyId" type="string">
  Property document ID to filter offers for a specific property
</ParamField>

<ParamField query="reservationId" type="string">
  Reservation external ID for in-stay offers
</ParamField>

<ParamField query="categoryId" type="number">
  Filter by offer category ID
</ParamField>

<ParamField query="redemptionType" type="string">
  Filter by redemption type: "direct", "externalCode", "propertySpecific", etc.
</ParamField>

<ParamField query="checkInDate" type="string">
  Check-in date for stay-based offers (ISO 8601 date)
</ParamField>

<ParamField query="latitude" type="number">
  Latitude for location-based offers (-90 to 90)
</ParamField>

<ParamField query="longitude" type="number">
  Longitude for location-based offers (-180 to 180)
</ParamField>

<ParamField query="radius" type="number">
  Search radius in kilometers (default: 50)
</ParamField>

<ParamField query="limit" type="number">
  Maximum number of offers to return (default: 20, max: 100)
</ParamField>

<ParamField query="offset" type="number">
  Number of offers to skip for pagination (default: 0)
</ParamField>

<RequestExample>

```bash cURL
curl -X GET "http://localhost:3000/v1/members/me/loyalty/offers?propertyId=abc123&limit=10" \
  -H "Authorization: Bearer YOUR_CLERK_JWT"
```

```typescript TypeScript
const response = await fetch('http://localhost:3000/v1/members/me/loyalty/offers?propertyId=abc123&limit=10', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_CLERK_JWT'
  }
});

const offers = await response.json();
```

</RequestExample>

## Response [#response]

<ResponseField name="items" type="array" required>
  List of available offers
  
  <Expandable title="array items">
    <ResponseField name="offerId" type="string" required>
      Offer document ID
    </ResponseField>
    
    <ResponseField name="name" type="string" required>
      Display name of the offer
    </ResponseField>
    
    <ResponseField name="shortDescription" type="string">
      Brief description for card display
    </ResponseField>
    
    <ResponseField name="description" type="string">
      Full description of the offer
    </ResponseField>
    
    <ResponseField name="pointsRequired" type="number" required>
      Points cost to claim this offer
    </ResponseField>
    
    <ResponseField name="retailValue" type="number">
      Retail value of the offer in dollars
    </ResponseField>
    
    <ResponseField name="discountAmount" type="number">
      Dollar amount of discount if applicable
    </ResponseField>
    
    <ResponseField name="discountType" type="string">
      Type of discount: "percentage", "fixed", etc.
    </ResponseField>
    
    <ResponseField name="redemptionType" type="string" required>
      How offer is redeemed: "direct", "externalCode", "propertySpecific", etc.
    </ResponseField>
    
    <ResponseField name="category" type="object">
      Offer category information
      
      <Expandable title="properties">
        <ResponseField name="id" type="number" required>
          Category ID
        </ResponseField>
        
        <ResponseField name="name" type="string" required>
          Category name
        </ResponseField>
      </Expandable>
    </ResponseField>
    
    <ResponseField name="heroImageUrl" type="string">
      URL for hero image
    </ResponseField>
    
    <ResponseField name="cardImageUrl" type="string">
      URL for card thumbnail image
    </ResponseField>
    
    <ResponseField name="howToRedeem" type="string">
      Instructions for redeeming the offer
    </ResponseField>
    
    <ResponseField name="termsAndConditions" type="string">
      Terms and conditions text
    </ResponseField>
    
    <ResponseField name="isEligible" type="boolean" required>
      Whether the member can claim this offer
    </ResponseField>
    
    <ResponseField name="eligibilityReason" type="string">
      Reason if not eligible (e.g., "Insufficient points", "Tier too low")
    </ResponseField>
    
    <ResponseField name="restrictions" type="array">
      Active restrictions preventing claim
      
      <Expandable title="array items">
        <ResponseField name="type" type="string" required>
          Restriction type: "requires_stay", "check_in_window"
        </ResponseField>
        
        <ResponseField name="message" type="string" required>
          Human-readable restriction message
        </ResponseField>
        
        <ResponseField name="details" type="object">
          Additional restriction details
        </ResponseField>
      </Expandable>
    </ResponseField>
    
    <ResponseField name="requiresStay" type="boolean" required>
      Whether offer requires an active reservation
    </ResponseField>
    
    <ResponseField name="disableBeforeCheckInHours" type="number">
      Hours before check-in when offer becomes unavailable
    </ResponseField>
    
    <ResponseField name="validUntil" type="string">
      ISO 8601 timestamp when offer expires
    </ResponseField>
    
    <ResponseField name="isCustomOffer" type="boolean">
      Whether this is a custom/personalized offer
    </ResponseField>
    
    <ResponseField name="isGlobal" type="boolean">
      Whether this offer is available globally
    </ResponseField>
    
    <ResponseField name="propertyDocumentId" type="string">
      Primary property document ID for property-specific offers
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="total" type="number" required>
  Total number of offers matching filters
</ResponseField>

<ResponseField name="offset" type="number">
  Current pagination offset
</ResponseField>

<ResponseField name="limit" type="number">
  Current pagination limit
</ResponseField>

<ResponseExample>

```json 200 Response
{
  "items": [
    {
      "offerId": "offer_spa_discount",
      "name": "Spa Treatment Discount",
      "shortDescription": "25% off all spa treatments",
      "description": "Enjoy a 25% discount on any spa treatment at our luxury wellness center",
      "pointsRequired": 1500,
      "retailValue": 200,
      "discountAmount": 50,
      "discountType": "percentage", 
      "redemptionType": "propertySpecific",
      "category": {
        "id": 3,
        "name": "Spa & Wellness"
      },
      "heroImageUrl": "https://cdn.journey.com/offers/spa-hero.jpg",
      "cardImageUrl": "https://cdn.journey.com/offers/spa-card.jpg",
      "howToRedeem": "Present your verification code at the spa reception",
      "termsAndConditions": "Valid for single use per stay. Subject to availability.",
      "isEligible": true,
      "eligibilityReason": null,
      "restrictions": [],
      "requiresStay": true,
      "disableBeforeCheckInHours": 24,
      "validUntil": "2024-12-31T23:59:59Z",
      "isCustomOffer": false,
      "isGlobal": false,
      "propertyDocumentId": "prop_luxury_resort"
    },
    {
      "offerId": "offer_dining_credit",
      "name": "Dining Credit",
      "shortDescription": "$75 dining credit",
      "description": "Enjoy a $75 credit towards any dining experience at our restaurants",
      "pointsRequired": 2000,
      "retailValue": 75,
      "redemptionType": "direct",
      "category": {
        "id": 1,
        "name": "Dining"
      },
      "heroImageUrl": "https://cdn.journey.com/offers/dining-hero.jpg",
      "cardImageUrl": "https://cdn.journey.com/offers/dining-card.jpg",
      "howToRedeem": "Credit will be automatically applied to your room account",
      "isEligible": false,
      "eligibilityReason": "Insufficient points (2000 required, 1800 available)",
      "restrictions": [
        {
          "type": "requires_stay",
          "message": "This offer requires an active reservation",
          "details": {}
        }
      ],
      "requiresStay": true,
      "disableBeforeCheckInHours": null,
      "validUntil": "2024-12-31T23:59:59Z",
      "isCustomOffer": false,
      "isGlobal": false,
      "propertyDocumentId": "prop_luxury_resort"
    }
  ],
  "total": 12,
  "offset": 0,
  "limit": 10
}
```

</ResponseExample>

## Offer Filtering [#offer-filtering]

### Property Context [#property-context]
- **propertyId**: Returns offers available at that specific property
- **reservationId**: Returns offers for your current/future stay at that property
- **checkInDate**: Filters offers based on your check-in date

### Location Context [#location-context]
- **latitude/longitude/radius**: Returns offers available within the specified area
- Useful for discovering offers near your current location

### Category Filtering [#category-filtering]
- **categoryId**: Filter by specific category like "Dining", "Spa & Wellness", "Activities"
- **redemptionType**: Filter by how offers are redeemed

## Related Endpoints [#related-endpoints]

- [Get Offer Details](/api-reference/members/loyalty/get-offer) - Get full details of a specific offer
- [Claim Offer](/api-reference/members/loyalty/claim-offer) - Purchase an offer with points
- [Get Wallet Balance](/api-reference/members/wallet/get-balance) - Check available points
