---
updatedAt: 2026-10-29T01:12:37.000Z
agentTools:
  projectIndex: https://wrenai.readme.io/llms.txt
---

# Generate a summary

Generates a natural language summary from a SQL query and a question

The `/v2/generate_summary` endpoint takes a user question and a SQL query, executes the SQL, and generates a natural language summary based on the result.

It is typically used after you've already generated or written a SQL query and want to provide an explanation for the data returned.

> 📘 When to use it
>
> * You’ve already written or generated SQL and want a natural summary of the result.
> * You want to provide a user-friendly explanation in dashboards, chat interfaces, or automated reports.
> * You need post-processing summarization after raw SQL execution.
>
> For a full pipeline (from question → SQL → result → summary), use the `/v1/ask` endpoint instead.

## How it works

* You provide the original natural language question and the sql that was run.
* The system runs the query, samples the result (default `500` rows), and generates a user-friendly answer in natural language.
* You can customize the sample size and language.

## Basic usage

```json Request
{
  "projectId": 1,
  "question": "List the top 5 states with the most customers",
  "sql": "SELECT customer_state, COUNT(*) as customer_count FROM customers GROUP BY customer_state ORDER BY customer_count DESC LIMIT 5"
}
```

```json Response
{
  "id": "b2c3d4e5-f6g7-8901-bcde-f23456789012",
  "answerId": "b2c3d4e5-f6g7-8901-bcde-f23456789012",
  "summary": "São Paulo (SP) leads with 15,847 customers, followed by Rio de Janeiro (RJ) and Minas Gerais (MG). These top 3 states account for over 50% of the customer base.",
  "threadId": "9c537507-9cec-46ed-b877-07bfa6322bed"
}
```

## Answer feedback

<Callout icon="📌" theme="info">
  Answer feedback is currently available on self-hosted Wren AI. Coming soon to Wren AI Cloud.
</Callout>

The response carries an `answerId` field. A failed call that Wren AI recorded returns one too, in the error body. Pass it to [Submit answer feedback](./post_answers-answerid-feedback) to let your users rate the answer. See [Getting an `answerId`](./answer_feedback#getting-an-answerid) for the rules every feedback-capable endpoint follows.

## Error handling

Common Error Codes

* `NO_DEPLOYMENT_FOUND` – No active deployment for the current project.
* `POLLING_TIMEOUT` – Timed out while waiting for AI response.
* `INVALID_SQL_ERROR` – The generated SQL could not be executed (e.g. due to a schema mismatch).
* `INTERNAL_SERVER_ERROR` – An unknown error occurred on the server.

# OpenAPI definition

```json
{
  "openapi": "3.0.0",
  "info": {
    "title": "WrenAI API",
    "description": "RESTful API for interacting with Wren AI.\n\n## Base URLs & versioning\nThe API version is part of each endpoint's path — every endpoint lives under `/api/v1/...` or `/api/v2/...`.\n- **v2** (canonical, recommended): the AI building blocks (`generate_sql`,\n  `run_sql`, `generate_summary`, `stream/generate_sql`,\n  `stream_explanation`), the interactive / adhoc ECharts endpoints\n  (`generate_chart`, `stream/ask`, `stream/interactive_ask` and their\n  `respond` side-channels), and all project / API-key / knowledge CRUD\n  endpoints. The building blocks and CRUD endpoints are also served under\n  `/api/v1` as identical aliases. The agentic project file endpoints\n  (`projects/{project_id}/files*`) are v2-only.\n\n- **v1**: the synchronous `ask`, the Vega-Lite `generate_vega_chart`, and\n  the legacy `stream/ask` / `stream/interactive_ask` streaming variants\n  (Vega-Lite output, no mid-stream clarification loop).\n\n\n## Authentication\nAll endpoints require an API key supplied as a Bearer token: `Authorization: Bearer <key>`. A project key (prefix `sk-`) authorizes only its own project; an organization key (prefix `osk-`) authorizes every project in the org. `POST /projects`, `GET /projects` and the organization endpoints (`/orgs/{org_id}/...`) require an org key.\n\n## Response envelope\nJSON responses from the AI building blocks and `generate_chart` are wrapped by a common envelope that prepends `id` (a UUID for the request) and `invalidSessionProperties` (string[]) to the documented payload. CRUD and project file endpoints (projects / keys / knowledge / files) return the documented payload directly without this envelope. Validation/auth pre-checks that fire before the handler body return a bare `{ \"error\": \"...\" }` (no `id`).\n\n## Server-Sent Events\nStreaming endpoints respond with `Content-Type: text/event-stream`. Frames are newline-delimited `data: {json}\\n\\n` records. Each endpoint documents its frame `type`s in its description.",
    "version": "1.2.0"
  },
  "servers": [
    {
      "url": "https://cloud.getwren.ai/api",
      "description": "Wren AI Cloud. The version prefix (/v1 or /v2) is part of each endpoint path."
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "tags": [
    {
      "name": "AI - SQL & Answers",
      "description": "Generate and run SQL, summarize results, and ask questions."
    }
  ],
  "paths": {
    "/v2/generate_summary": {
      "post": {
        "tags": [
          "AI - SQL & Answers"
        ],
        "operationId": "generateSummary",
        "summary": "Summarize the result of a SQL query",
        "description": "Executes the SQL (sampled), then generates a natural language summary of the result. Served under both `/api/v1` and `/api/v2`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/SessionPropertiesHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "projectId",
                  "question",
                  "sql"
                ],
                "properties": {
                  "projectId": {
                    "type": "integer"
                  },
                  "question": {
                    "type": "string",
                    "description": "The question the summary should answer."
                  },
                  "sql": {
                    "type": "string",
                    "description": "The SQL whose result is summarized."
                  },
                  "sampleSize": {
                    "type": "integer",
                    "default": 500,
                    "description": "Maximum number of rows previewed for the summary."
                  },
                  "language": {
                    "type": "string"
                  },
                  "threadId": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successfully generated summary",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "answerId": {
                      "$ref": "#/components/schemas/AnswerId"
                    },
                    "invalidSessionProperties": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "summary": {
                      "type": "string"
                    },
                    "threadId": {
                      "type": "string"
                    },
                    "usage": {
                      "$ref": "#/components/schemas/Usage"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request (missing fields, `NO_DEPLOYMENT_FOUND`, `INVALID_SQL_ERROR`, or summary generation failure).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnswerErrorResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "500": {
            "description": "Internal server error (e.g. `POLLING_TIMEOUT`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnswerErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key supplied as a Bearer token. Use a project key (prefix `sk-`) for access to a single project, or an organization key (prefix `osk-`) for access to all projects in the org. `POST /projects` and `GET /projects` require an org key."
      }
    },
    "parameters": {
      "SessionPropertiesHeader": {
        "name": "X-Wren-Session-Properties",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string"
        },
        "description": "Comma-separated `key=value` pairs applied as row/column-level security session properties (e.g. `region=US,tier=pro`). Unknown keys are echoed back in the `invalidSessionProperties` response field."
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Invalid or missing API key.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "MethodNotAllowed": {
        "description": "Method not allowed.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    },
    "schemas": {
      "Usage": {
        "type": "object",
        "description": "Token usage for the request, including a per-LLM-call breakdown. Present when the AI service reports usage.",
        "properties": {
          "inputTokens": {
            "type": "integer",
            "description": "Total input tokens across all LLM calls."
          },
          "outputTokens": {
            "type": "integer",
            "description": "Total output tokens across all LLM calls."
          },
          "cachedTokens": {
            "type": "integer",
            "description": "Cached input tokens, when reported."
          },
          "totalTokens": {
            "type": "integer",
            "description": "Total tokens (input + output)."
          },
          "llmCalls": {
            "type": "array",
            "description": "Per-LLM-call usage breakdown.",
            "items": {
              "type": "object",
              "properties": {
                "step": {
                  "type": "string",
                  "description": "The pipeline step that made the call (e.g. \"sql_generation\")."
                },
                "inputTokens": {
                  "type": "integer"
                },
                "outputTokens": {
                  "type": "integer"
                },
                "totalTokens": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "description": "Standard error body. Errors raised inside a handler also carry a top-level `id` (UUID) and may carry a `code`; validation/auth pre-checks return only `error`.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the error response (handler-raised errors only)."
          },
          "error": {
            "type": "string",
            "description": "Error message."
          },
          "code": {
            "type": "string",
            "description": "Machine-readable error code (when applicable)."
          }
        }
      },
      "AnswerId": {
        "type": "string",
        "description": "Identifies this answer for the feedback API (`POST /v2/answers/{answerId}/feedback`). Returned on failures too, whenever the call was recorded. Send it back exactly as returned. Answer feedback is currently available on self-hosted Wren AI; coming soon to Wren AI Cloud.",
        "example": "3f1c9a52-7d4e-4b8a-9c61-2e5f0b7a8d13"
      },
      "AnswerErrorResponse": {
        "description": "Error body of a call that produces an answer. Carries `answerId` when the failed call was recorded.",
        "allOf": [
          {
            "$ref": "#/components/schemas/ErrorResponse"
          },
          {
            "type": "object",
            "properties": {
              "answerId": {
                "$ref": "#/components/schemas/AnswerId"
              }
            }
          }
        ]
      }
    }
  }
}
```