# DYLI Read API — complete integration reference

Version: `v1.1`  
Production base URL: `https://www.dyli.io/api/public/v1`  
Purpose: public catalog, marketplace, user, collection, activity, verification, and analytics data. Read routes do not create purchases, shipments, listings, or other side effects. `POST /metadata/advanced` is a read-only batch lookup.

## Authentication

Create a key at `https://www.dyli.io/requestapi`. Send it from a trusted server with either header:

```http
x-api-key: dyli_live_...
```

```http
Authorization: Bearer dyli_live_...
```

Read routes accept keys with `read`, `commerce`, or `write` scope. Do not expose a key in browser or mobile code. Legacy read routes may accept `apiKey` or `apikey` in the query string, but header authentication is the production contract.

## First request

```bash
curl "https://www.dyli.io/api/public/v1/listings?page=1&pageSize=25" \
  -H "x-api-key: $DYLI_API_KEY"
```

Call `GET /overview` to discover the current route inventory and enabled/coming-soon state. Do not infer a route's availability from a static document when the overview says otherwise.

## Common conventions

- Responses are JSON.
- IDs are not interchangeable: `product_id` identifies a DYLI product, `token_id` identifies an ERC-1155 token, `listing_id` identifies a market listing, `box_id` identifies a Box, and `cert` identifies a graded collectible.
- Product rows usually include canonical `url` or `dyli_url` fields. Token rows may include `metadata_url` and `metadata_advanced_url`.
- Money is normally expressed in USD unless the response names another currency.
- Dates are ISO 8601 UTC timestamps.
- Product filters are case-insensitive where documented.
- Read prices are discovery data. Use the Commerce API for a server-priced purchase quote.

### Product filters

Catalog-style endpoints commonly accept:

| Parameter | Meaning |
| --- | --- |
| `brand` | Partial, case-insensitive brand match. |
| `category` | Partial, case-insensitive category match. |
| `subcategory` | Partial, case-insensitive subcategory match. |
| `cert` | Certificate number; common BGS variants are checked. |
| `productId` / `product_id` | Exact DYLI product ID. |
| `tokenId` / `tokenid` | Exact token ID. |
| `marketType` / `market_type` | `primary` for DYLI first-sale inventory or `secondary` for user resale inventory. |

### Pagination

Most endpoints use 1-based `page` and `pageSize`; some accept `limit` as an alias. A normal pagination object is:

```json
{
  "pagination": {
    "page": 1,
    "page_size": 25,
    "total": 120,
    "total_pages": 5,
    "has_more": true
  }
}
```

Holdings and Box history support cursors. Redemptions use `limit` and `offset`.

## Endpoint map

### Discovery and metadata

| Method and path | Inputs | Returns |
| --- | --- | --- |
| `GET /overview` | None | Live endpoint inventory, controls, key requirements, and documentation links. |
| `GET /search` | `q`, product filters, `onlyListed`, `page`, `pageSize` | Products matching text, taxonomy, identifiers, or current market availability. |
| `GET /products/{productId}/cert` | Product ID in path | Product name, created date, price, `has_cert`, cert number, grader, and grade. |
| `GET /metadata/{tokenId}` | Token ID in path | Basic token/product metadata plus market and availability context. |
| `GET /metadata/advanced/{tokenId}` | Token ID in path | Rich images, normalized collectible fields, alternate IDs, and pricing context. |
| `GET /metadata/advanced` | `tokenIds=1,2,...`, maximum 50 | Batch advanced metadata. |
| `POST /metadata/advanced` | JSON token-ID array, maximum 50 | Same read-only batch result as the GET route. |
| `GET /contracts` | None | Current public contract groups, roles, addresses, chain, and chain ID. |

Search parameters:

- `q` aliases: `query`, `searchTerm`.
- `onlyListed` defaults to `true`; alias `only_listed`.
- `pageSize` maximum is 100; `limit` is an alias.
- Search rows include product identity, images/taxonomy, canonical links, `pricing.primary`, `pricing.secondary`, `availability`, and `market_flags`.

Market snapshot fields:

- `pricing.primary`: current primary price, quantity available, and listing count.
- `pricing.secondary`: current secondary floor and listing count.
- `availability.primary_quantity_available` and `primary_listing_count`.
- `availability.secondary_listing_count`.
- `availability.in_boxes_quantity`.
- `availability.in_circulation_quantity`, `total_minted`, and `total_redeemed` when available.

### Marketplace

| Method and path | Inputs | Returns |
| --- | --- | --- |
| `GET /listings` | Product filters, `marketType`, `page`, `pageSize` | Active primary and secondary DYLI listings; eBay is separate. |
| `GET /ebay/listings` | `id`, `q`, `seller`, `brand`, `grade`, `minPrice`, `maxPrice`, `sort`, `page`, `limit` | Approved eBay inventory, including PSA Vault. |
| `GET /offers` | `status`, product filters, `sort`, `direction`, pagination | Active or accepted secondary offers. |
| `GET /sales` | Product filters, `marketType`, `boxId`, time bounds, pagination | Normalized purchases, resales, Fair Drops, Boxes, claims, and eBay-origin activity. |
| `GET /boxes/{boxId}/reports/rollups` | Box ID | Private daily-email financial rollups for the Box owner or a true admin. |
| `GET /boxes/{boxId}/reports/orders` | `category`, `rowType`, pagination, `format` | Private Box order/export rows as JSON or CSV. |
| `GET /boxes/{boxId}/reports/adjustments` | `rowType`, pagination, `format` | Private Box adjustment rows as JSON or CSV. |
| `GET /redemptions` | Required `productIds`; `limit`, `offset` | Completed shipment, rip, and grading redemptions. |
| `GET /p2p-trades` | Participant/directional filters, contract version, accepted time bounds, pagination | Accepted collector-to-collector trades. Alias: `/p2p-trading`. |

Listings:

- `pageSize` maximum is 200.
- Rows include `listing_id`, `product_id`, `token_id`, `name`, links, `market_type`, `market_flags`, `source_marketplace`, `price`, `currency`, `quantity_available`, `listing_count`, `pricing`, `availability`, image/taxonomy/cert, and `updated_at`.
- A product may have primary inventory, secondary listings, both, or neither.
- To buy, use the matching Commerce catalog row and pass its `purchase.quote_item` unchanged.

eBay:

- `sort` is `priceAsc`, `priceDesc`, or `newest`.
- Only approved sellers are returned; PSA is the default approved source.
- Use `id={ebay_item_id}` for one exact item.
- Rows include `listing_id`, `item_id`, seller, images, condition, price, shipping estimate, currency, quantity, vault/provider flags, and buying context.
- The Read API is discovery-only. Use `GET /api/commerce/v1/catalog/ebay` and the Commerce API to purchase supported inventory.

Offers:

- `status`: `active`, `accepted`, or `all`; default `active`.
- `sort`: `price`, `created`, or `expiration`; default `price`.
- `direction`: `asc` or `desc`; default `desc`.
- `pageSize` maximum is 200.
- Rows include offer/order/reservoir IDs, product/token identity, price/currency/quantity, status, offerer and maker, acceptance/expiry fields, transaction hash, taxonomy, and links.

Sales:

- Time bounds: `createdAfter` / `createdBefore`; aliases `created_after`, `created_before`, `from`, `to`.
- `boxId` alias: `box_id`.
- `pageSize` maximum is 200.
- Use `market_type` for primary versus secondary. Use `sale_channel` for checkout, secondary, Fair Drop, Box, eBay, or claim classification.

Redemptions:

- `productIds` is required and accepts one ID, comma-separated IDs, or repeated parameters. Aliases: `productids`, `productId`, `productid`.
- `limit` defaults to 250 and has a maximum of 1000; `offset` defaults to 0.
- All requested products are combined and sorted newest first.
- `type` is `shipment`, `rip`, or `grade`. Trade-ins are excluded.
- Optional `collection` contains a submitted redemption field with `label`, `type`, and `value`.

P2P trades:

- `participant`, `username`, or `wallet` matches either side.
- Directional filters: `from`, `to`, `fromUsername`, `toUsername`, `fromWallet`, `toWallet`.
- `contractVersion` is `new` or `legacy`; alias `contract_version`.
- Time bounds: `acceptedAfter` / `acceptedBefore`; aliases `createdAfter`, `createdBefore`, `fromDate`, `toDate`.
- Only accepted trades are public. Rows include parties, USDC.e on each side, item arrays, contract version/address, and timestamps.

### Users and collections

| Method and path | Inputs | Returns |
| --- | --- | --- |
| `GET /users/{identifier}` | Username, `@username`, or EVM wallet | Basic public profile and wallet information for any collector. |
| `GET /sellers/{identifier}` | Username, `@username`, or EVM wallet; product filters and pagination | Public seller profile, X handle, wallets, products, Boxes, Fair Drop state, and counts. |
| `GET /holdings/{identifier}` | Username or wallet; cursor/page options, `includeTotals`, `includeValue` | Live token balances and optional estimated collection value. |
| `GET /sets/{collection}` | Optional collector `identifier` | Set catalog and collector progress. |
| `GET /sets/{collection}/{setCode}` | Collector and availability filters, pagination | Cards, ownership, market prices, offers, and set links. |
| `GET /sets/{collection}/{setCode}/missing` | Required/optional collector, availability, and max-price filters | Missing-card matches and completion summary. |

Holdings:

- `pageSize` maximum is 100; alias `limit`.
- Prefer `cursor` with the returned `pagination.next_cursor`.
- `includeTotals=true` scans the wallet for total token/balance counts.
- `includeValue=true` scans the wallet for full `collection_value` and is more expensive.
- Valuations are estimates, not bids or guaranteed liquidation values.

Sets:

- Supported collection keys include `vibes`, `azuki`, `pokemon`, `pokemon_jp`, `onepiece`, `magic`, `yugioh`, `starwars`, `dragonball`, and `disney`.
- Collector aliases: `identifier`, `user`, `username`, `wallet`, `address`.
- `missing=true` returns unowned cards.
- `onlyAvailable=true` / `available=true` requires a current offer.
- `maxPrice` / `max_price` caps the offer price.
- `pageSize` defaults to 25 and has a maximum of 100.
- Missing results include missing count, buyable count, total cost of matches, remaining count, ownership, offer, and canonical-link fields.

### Boxes and Fair Drops

| Method and path | Inputs | Returns |
| --- | --- | --- |
| `GET /boxes` | `page`, `pageSize`, `chaseLimit`, optional `boxId` | Live Box summaries, EV, inventory, top chases, odds, and availability. |
| `GET /boxes/{boxId}` | Box ID | One Box summary. |
| `GET /boxes/{boxId}/ranges` | `includeItems`, nested item pagination | Odds ranges and current inventory count/value per range. |
| `GET /boxes/{boxId}/history` | `cursor`, `since_id`, `include_box` | Cursor-paginated completed pull history. |
| `GET /boxes/verify` | `orderId` or `txHash`; pagination | Completed pull, RNG, selected range, odds, and prize-pool verification. |
| `GET /fair-drops` | `status`, `q`, pagination | Current or historical Fair Drops. |
| `GET /fair-drops/{dropId}/verify` | Drop ID; pagination | Entries, participant odds, winner, and verification number. |
| `GET /fair-drops/verify` | `txHash`; pagination | Direct Fair Drop verification by order transaction. |

Boxes:

- `/boxes` defaults to `pageSize=12`, maximum 24. `chaseLimit` defaults to 6, maximum 12.
- Box summaries include prices/EV, FMV ratio, average value, inventory, top remaining chases, odds buckets, buyback data, and restocking/out-of-stock/live flags.
- `/ranges?includeItems=true` defaults to 25 items per range, maximum 100.
- History uses `next_cursor`; `since_id` supports incremental newer-row reads.
- Verification needs either `orderId` or `txHash`, not both.

Fair Drops:

- `status`: `pending`, `completed`, `refundable`, or `all`; default `pending`.
- `q` searches name or numeric drop ID.
- List `pageSize` maximum is 24; verification participant page maximum is 100.
- Rows include product/prize identity, entry price and payment type, entry counts, minimum state, seller/creator, winner when available, start/end/duration, and links.

### Digital packs and analytics

| Method and path | Inputs | Returns |
| --- | --- | --- |
| `GET /digital-packs` | Required/optional `productId`, pagination | Pack product, price, sealed/opened counts, and recent public activity. |
| `GET /digital-packs/{productId}` | Product ID; pagination | Same result for one pack product. |
| `GET /transactions` | `timeframe`, pagination | GMV and transaction-count rollups. |
| `GET /rewards` | `type`, `month`, `limit` | Diamond and/or monthly ticket leaderboards. |
| `GET /referrals` | None | Refer & Earn program start and current Standard/Pro rates. |

- Digital pack `pageSize` defaults to 10 and has a maximum of 50. Private wallet balances and pending settlements are excluded.
- Transaction `timeframe` is `day`, `month`, or `total`; default `day`.
- Rewards `type` is `all`, `diamonds`, or `tickets`; `month` is `YYYY-MM`; `limit` maximum is 250.

## Errors and retries

```json
{ "error": "Invalid API key" }
```

| Status | Meaning and action |
| --- | --- |
| `400` | Invalid query, body, ID, or timestamp. Fix the request. |
| `401` | Missing API key. |
| `403` | Invalid, disabled, revoked, or expired key. Replace or reissue it. |
| `404` | Resource not found or route disabled. |
| `405` | Method not allowed. |
| `429` | Rate limited. Wait for `Retry-After` and use bounded backoff. |
| `500` | Server/upstream error. Retry safe reads with capped exponential backoff and jitter. |
| `503` | Route is known but currently unavailable. Do not treat it as live. |

## Integration checklist

1. Keep the API key on the server.
2. Call `/overview` during startup or health checks.
3. Use canonical IDs and links returned by the API; do not derive identifiers.
4. Encode query parameters normally; use `curl --get --data-urlencode` in scripts.
5. Follow pagination until `has_more` is false or `next_cursor` is null.
6. Treat prices as discovery data and use Commerce quotes for checkout.
7. Respect `Retry-After` and cache stable metadata where appropriate.

Human-readable docs: `https://www.dyli.io/docs/api/read-apis`  
Commerce reference: `https://www.dyli.io/docs/llms/commerce-api.md`
