---
title: "Public: search promotional offers across visible firms. Defaults to live (active, unexpired) offers. Pass propfirmId for one firm's offers, or challengeId for offers that apply to a challenge (firm-wide offers included)."
method: GET
path: "/api/propfirms/offers/query"
tags: ["propfirms"]
---

# Public: search promotional offers across visible firms. Defaults to live (active, unexpired) offers. Pass propfirmId for one firm's offers, or challengeId for offers that apply to a challenge (firm-wide offers included).

`GET /api/propfirms/offers/query`

## Request

- Base URL: `https://app.luxalgo.com`
- URL: `https://app.luxalgo.com/api/propfirms/offers/query`
- Auth: none declared
- TypeScript: <https://skmtc.dev/luxalgo/apis/luxalgo-public-api/docs/api/propfirms/offers/query/get.ts> (a function with typed inputs; its response is checked against the schema)

## Query parameters

- `offerId` string: Comma-separated public offer ids.
- `promoCode` string: Case-insensitive substring of the promo code.
- `offerText` string: Case-insensitive search over promo code and offer descriptions.
- `isActive` 'true' | 'false': Defaults to live offers only. Pass false to look at inactive offers.
- `isFeatured` 'true' | 'false': Boolean filter as "true" or "false".
- `discountIsPercent` 'true' | 'false': Boolean filter as "true" or "false".
- `discountMin` string: Minimum discount value (percent or absolute, matching discountIsPercent).
- `discountMax` string: Maximum discount value.
- `includeInactive` 'true' | 'false': When true, inactive offers are not hidden. Defaults to false.
- `includeExpired` 'true' | 'false': When true, ended offers are not hidden. Defaults to false.
- `pageIndex` string: 0-based page index. Defaults to 0.
- `pageQuantity` string: Page size. Defaults to 50, capped at 100.
- `direction` 'asc' | 'desc': Sort direction. Defaults per sort key.
- `text` string: Case-insensitive search over promo code, descriptions, and firm name/slug.
- `firmId` string: Comma-separated internal firm ids.
- `propfirmId` string: Comma-separated public firm slugs.
- `challengeId` string: Comma-separated challenge ids. An offer matches when it applies to at least one (all-challenges offers match that firm's challenges).
- `sort` 'discountValue' | 'endsAt' | 'promoCode': Defaults to featured first, then discount.

## Response `200`

Success. The payload is wrapped in the standard { data, errors } envelope.

- object
  - `data` object, required
    - `offers` object[], required
      - `offerId` string, required
      - `firmId` string, required
      - `propfirmId` string, required
      - `propfirmName` string, required
      - `promoCode` string, nullable, required
      - `affiliateLink` string, nullable, required
      - `discountIsPercent` boolean, required
      - `discountValue` number, nullable, required
      - `shortDescription` string, nullable, required
      - `fullDescription` string, nullable, required
      - `isActive` boolean, required
      - `isFeatured` boolean, required
      - `hasEndDate` boolean, required
      - `endsAt` string, nullable, required
      - `scope` union, required
        - object
          - `type` 'all_challenges', required
        - object
          - `type` 'specific_challenges', required
          - `challengeIds` string[], required
    - `count` number, required
  - `errors` unknown

## Other responses

- `400`: Validation error — errors[].details carries the zod issues.
- `500`: Unexpected server error.

---

[API](https://skmtc.dev/luxalgo/apis/luxalgo-public-api.md) - [All operations](https://skmtc.dev/luxalgo/apis/luxalgo-public-api/llms.txt) - [OpenAPI document](https://skmtc.dev/luxalgo/apis/luxalgo-public-api/revisions/226c2d642643?raw)
