> ## Documentation Index
> Fetch the complete documentation index at: https://docs.waffo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# GraphQL API

> 通过 GraphQL 只读查询访问所有数据

## 概述

Waffo Pancake GraphQL API 提供对所有数据的**只读**访问。写操作使用 REST action 端点，查询使用 GraphQL。

```
POST /v1/graphql
```

**认证方式：** API Key

<Note>
  GraphQL API 仅支持**查询（Query）**。所有写操作（创建、更新、删除）使用 [REST action 端点](/api-reference/introduction#endpoint-groups)。
</Note>

## 发送请求

### 请求体

| 字段          | 类型     | 必需 | 说明            |
| ----------- | ------ | -- | ------------- |
| `query`     | string | 是  | GraphQL 查询字符串 |
| `variables` | object | 否  | 查询变量          |

<CodeGroup>
  ```typescript SDK theme={"system"}
  import { WaffoPancake } from "@waffo/pancake-ts";

  const client = new WaffoPancake({
    merchantId: process.env.WAFFO_MERCHANT_ID!,
    privateKey: process.env.WAFFO_PRIVATE_KEY!,
  });

  interface StoresQuery {
    stores: Array<{ id: string; name: string; status: string }>;
  }

  const result = await client.graphql.query<StoresQuery>({
    query: `{ stores { id name status } }`,
  });
  console.log(result.stores);
  // => [{ id: "STO_2aUyqjCzEIiEcYMKj7TZtw", name: "My Store", status: "active" }]
  ```

  ```typescript TypeScript (fetch) theme={"system"}
  // Uses callApi() helper from authentication.mdx
  const result = await callApi("POST", "/v1/graphql", {
    query: "query { stores { id name status } }",
    variables: {},
  });
  console.log(result.data.stores);
  // => [{ id: "STO_2aUyqjCzEIiEcYMKj7TZtw", name: "My Store", status: "active" }]
  ```

  ```java Java theme={"system"}
  // Uses callApi() helper from authentication.mdx
  String body = """
      {"query":"query { stores { id name status } }","variables":{}}""";

  String response = callApi("POST", "/v1/graphql", body);
  System.out.println(response);
  // => {"data":{"stores":[{"id":"STO_2aUyqjCzEIiEcYMKj7TZtw","name":"My Store","status":"active"}]}}
  ```

  ```python Python theme={"system"}
  # Uses call_api() helper from authentication.mdx
  result = call_api("POST", "/v1/graphql", {
      "query": "query { stores { id name status } }",
      "variables": {},
  })
  stores = result["data"]["stores"]
  print(stores)
  # => [{"id": "STO_2aUyqjCzEIiEcYMKj7TZtw", "name": "My Store", "status": "active"}]
  ```

  ```go Go theme={"system"}
  // Uses callAPI() helper from authentication.mdx
  body := map[string]interface{}{
      "query":     "query { stores { id name status } }",
      "variables": map[string]interface{}{},
  }
  result, err := callAPI("POST", "/v1/graphql", body)
  if err != nil {
      log.Fatal(err)
  }
  fmt.Println(string(result))
  // => {"data":{"stores":[{"id":"STO_2aUyqjCzEIiEcYMKj7TZtw","name":"My Store","status":"active"}]}}
  ```

  ```rust Rust theme={"system"}
  // Uses call_api() helper from authentication.mdx
  let body = serde_json::json!({
      "query": "query { stores { id name status } }",
      "variables": {}
  });
  let result = call_api("POST", "/v1/graphql", &body).await?;
  println!("{}", result);
  // => {"data":{"stores":[{"id":"STO_2aUyqjCzEIiEcYMKj7TZtw","name":"My Store","status":"active"}]}}
  ```

  ```c C theme={"system"}
  /* Uses call_api() helper from authentication.mdx */
  const char *body = "{\"query\":\"query { stores { id name status } }\",\"variables\":{}}";
  char *response = call_api("POST", "/v1/graphql", body);
  printf("%s\n", response);
  free(response);
  ```

  ```cpp C++ theme={"system"}
  // Uses callApi() helper from authentication.mdx
  std::string body = R"({"query":"query { stores { id name status } }","variables":{}})";
  std::string response = callApi("POST", "/v1/graphql", body);
  std::cout << response << std::endl;
  // => {"data":{"stores":[{"id":"STO_2aUyqjCzEIiEcYMKj7TZtw","name":"My Store","status":"active"}]}}
  ```

  ```bash cURL theme={"system"}
  MERCHANT_ID="MER_2aUyqjCzEIiEcYMKj7TZtw"
  TIMESTAMP=$(date +%s)
  BODY='{"query":"query { stores { id name status } }","variables":{}}'
  BODY_HASH=$(echo -n "$BODY" | openssl dgst -sha256 -binary | base64 -w 0)
  CANONICAL_REQUEST="POST
  /v1/graphql
  $TIMESTAMP
  $BODY_HASH"

  SIGNATURE=$(echo -n "$CANONICAL_REQUEST" | openssl dgst -sha256 -sign private_key.pem | base64 -w 0)

  curl -X POST "https://api.waffo.ai/v1/graphql" \
    -H "Content-Type: application/json" \
    -H "X-Merchant-Id: $MERCHANT_ID" \
    -H "X-Timestamp: $TIMESTAMP" \
    -H "X-Signature: $SIGNATURE" \
    -d "$BODY"
  ```

  ```bash wget theme={"system"}
  MERCHANT_ID="MER_2aUyqjCzEIiEcYMKj7TZtw"
  TIMESTAMP=$(date +%s)
  BODY='{"query":"query { stores { id name status } }","variables":{}}'
  BODY_HASH=$(echo -n "$BODY" | openssl dgst -sha256 -binary | base64 -w 0)
  CANONICAL_REQUEST="POST
  /v1/graphql
  $TIMESTAMP
  $BODY_HASH"

  SIGNATURE=$(echo -n "$CANONICAL_REQUEST" | openssl dgst -sha256 -sign private_key.pem | base64 -w 0)

  wget -qO- "https://api.waffo.ai/v1/graphql" \
    --header="Content-Type: application/json" \
    --header="X-Merchant-Id: $MERCHANT_ID" \
    --header="X-Timestamp: $TIMESTAMP" \
    --header="X-Signature: $SIGNATURE" \
    --post-data="$BODY"
  ```
</CodeGroup>

### 状态码

| 状态码 | 说明                                 |
| --- | ---------------------------------- |
| 200 | 查询成功（GraphQL 错误在响应体的 `errors` 字段中） |
| 400 | 缺少查询 / 深度超限 / 无效环境 / 缺少或无效角色       |
| 401 | 认证失败                               |
| 403 | 不允许的操作类型（仅支持 Query）                |
| 500 | 内部服务器错误                            |

***

## Schema 内省

<Tip>
  **推荐：** 使用标准 GraphQL 内省查询来发现完整 Schema。这确保您始终使用最新的类型和字段。
</Tip>

<Warning>
  **GraphQL 类型与 REST/SDK 类型不同。** 例如，`prices` 在 REST 中是 `Record<string, PriceInfo>`（对象 map），但在 GraphQL 中是 `[CurrencyPrice!]!`（`{currency, priceInfo}` 数组）；`metadata` 在 REST 中是解析后的对象，但在 GraphQL 中是 JSON 字符串。请勿使用 SDK TypeScript 类型定义来构造 GraphQL 查询——始终使用内省或以下示例。
</Warning>

### 查询所有可用查询

```graphql theme={"system"}
query {
  __schema {
    queryType {
      fields {
        name
        description
        args {
          name
          type { name kind }
        }
      }
    }
  }
}
```

### 查询类型字段

```graphql theme={"system"}
query {
  __type(name: "Store") {
    name
    fields {
      name
      type { name kind ofType { name } }
    }
  }
}
```

API Key 认证授予您访问 **18 种查询类型**，包括单实体查询、带过滤的列表查询、计数查询和分析查询。

***

## 过滤

GraphQL 查询支持使用类型化过滤对象进行过滤：

| 类型               | 运算符                                  | 示例                                                     |
| ---------------- | ------------------------------------ | ------------------------------------------------------ |
| `StringFilter`   | `eq`, `ne`, `in`, `contains`         | `{ storeId: { eq: "STO_xxx" } }`                       |
| `DateTimeFilter` | `eq`, `gt`, `lt`, `gte`, `lte`       | `{ createdAt: { gte: "2026-01-01" } }`                 |
| `IntFilter`      | `eq`, `gt`, `lt`, `gte`, `lte`       | `{ attemptCount: { gte: 3 } }`                         |
| `AmountFilter`   | `eq`, `ne`, `gt`, `gte`, `lt`, `lte` | `{ amount: { gte: "9.99" }, currency: { eq: "USD" } }` |
| `BooleanFilter`  | `eq`                                 | `{ isActive: { eq: true } }`                           |

<Note>
  `AmountFilter` 的值为货币主单位的十进制字符串（如 `"9.99"`）。金额过滤条件**必须**在同一 `filter` 对象中搭配 `currency: { eq: "..." }`（单币种）使用。不支持跨币种金额比较。
</Note>

```graphql theme={"system"}
query {
  onetimeProducts(
    filter: {
      storeId: { eq: "STO_3bVzrkD0FJjFdZNLk8Ualx" }
      status: { eq: "active" }
    }
  ) {
    id
    name
    prices
  }
}
```

***

## 分页

使用 `limit` 和 `offset` 进行分页。使用 `*Count` 查询获取总数。

```graphql theme={"system"}
query {
  onetimeProducts(
    filter: { storeId: { eq: "STO_3bVzrkD0FJjFdZNLk8Ualx" } }
    limit: 10
    offset: 0
  ) {
    id
    name
  }
  onetimeProductsCount(
    filter: { storeId: { eq: "STO_3bVzrkD0FJjFdZNLk8Ualx" } }
  )
}
```

| 参数       | 类型      | 说明       |
| -------- | ------- | -------- |
| `limit`  | integer | 返回的最大结果数 |
| `offset` | integer | 跳过的结果数   |

***

## 环境相关字段

API Key 的环境影响返回的商品数据：

* `version` -- 返回指定环境的版本
* `status` -- 返回指定环境中的状态

一个商品可能在 test 环境中是 `active`，但在 production 环境中是 `inactive`（如果尚未发布）。

***

## 查询示例

<CardGroup cols={2}>
  <Card title="门店与商品" icon="store" href="/api-reference/endpoints/graphql/stores-and-products">
    查询门店、一次性商品、订阅商品和商品版本
  </Card>

  <Card title="订单与支付" icon="cart-shopping" href="/api-reference/endpoints/graphql/orders-and-payments">
    查询订单、订阅订单、支付和退款工单
  </Card>

  <Card title="数据分析" icon="chart-line" href="/api-reference/endpoints/graphql/analytics">
    收入统计、支付分析、趋势分析和客户洞察
  </Card>
</CardGroup>
