Exa Answer
curl --request POST \
--url https://api.novita.ai/v3/exa/answer \
--header 'Authorization: <authorization>' \
--header 'Content-Type: <content-type>' \
--data '
{
"query": "<string>",
"text": true,
"outputSchema": {
"type": "<string>",
"properties": {},
"required": [
"<string>"
],
"description": "<string>",
"additionalProperties": {}
}
}
'import requests
url = "https://api.novita.ai/v3/exa/answer"
payload = {
"query": "<string>",
"text": True,
"outputSchema": {
"type": "<string>",
"properties": {},
"required": ["<string>"],
"description": "<string>",
"additionalProperties": {}
}
}
headers = {
"Content-Type": "<content-type>",
"Authorization": "<authorization>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': '<content-type>', Authorization: '<authorization>'},
body: JSON.stringify({
query: '<string>',
text: true,
outputSchema: {
type: '<string>',
properties: {},
required: ['<string>'],
description: '<string>',
additionalProperties: {}
}
})
};
fetch('https://api.novita.ai/v3/exa/answer', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.novita.ai/v3/exa/answer",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'query' => '<string>',
'text' => true,
'outputSchema' => [
'type' => '<string>',
'properties' => [
],
'required' => [
'<string>'
],
'description' => '<string>',
'additionalProperties' => [
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: <content-type>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.novita.ai/v3/exa/answer"
payload := strings.NewReader("{\n \"query\": \"<string>\",\n \"text\": true,\n \"outputSchema\": {\n \"type\": \"<string>\",\n \"properties\": {},\n \"required\": [\n \"<string>\"\n ],\n \"description\": \"<string>\",\n \"additionalProperties\": {}\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "<content-type>")
req.Header.Add("Authorization", "<authorization>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.novita.ai/v3/exa/answer")
.header("Content-Type", "<content-type>")
.header("Authorization", "<authorization>")
.body("{\n \"query\": \"<string>\",\n \"text\": true,\n \"outputSchema\": {\n \"type\": \"<string>\",\n \"properties\": {},\n \"required\": [\n \"<string>\"\n ],\n \"description\": \"<string>\",\n \"additionalProperties\": {}\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.novita.ai/v3/exa/answer")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = '<content-type>'
request["Authorization"] = '<authorization>'
request.body = "{\n \"query\": \"<string>\",\n \"text\": true,\n \"outputSchema\": {\n \"type\": \"<string>\",\n \"properties\": {},\n \"required\": [\n \"<string>\"\n ],\n \"description\": \"<string>\",\n \"additionalProperties\": {}\n }\n}"
response = http.request(request)
puts response.read_body{
"requestId": "string",
"answer": "string",
"citations": [
{
"id": "string",
"title": "string",
"url": "string",
"publishedDate": "string",
"author": "string",
"text": "string"
}
]
}
{
"code": 400,
"reason": "INVALID_REQUEST_BODY",
"message": "Invalid request body | Validation error: expected string, received undefined at \"query\"",
"metadata": {
"trace_id": "0748a32faccde3d924752336fd5c1a31"
}
}
{
"code": 403,
"reason": "INVALID_API_KEY",
"message": "invalid api-key",
"metadata": {}
}
{
"code": 404,
"reason": "PATH_NOT_FOUND",
"message": "path not found for model",
"metadata": {
"trace_id": "3c3433f0cb475a04f9a4969b8c6ed903"
}
}
{
"code": 429,
"reason": "RATE_LIMIT_EXCEEDED",
"message": "rate limit exceeded, please retry later",
"metadata": {
"trace_id": "5f2a9c7e41b8d0a36e9f4c2b7d81a0e5"
}
}
{
"code": 500,
"reason": "TASK_FAILED",
"message": "upstream provider temporarily unavailable, please retry",
"metadata": {
"trace_id": "8846379c692d7218173460afe95640f1"
}
}
{
"code": 503,
"reason": "SERVICE_UNAVAILABLE",
"message": "service temporarily unavailable",
"metadata": {
"trace_id": "b7e3f1a9d24c05e8f63a1b9c7e05d2f4"
}
}
Exa
Exa Answer
POST
/
v3
/
exa
/
answer
Exa Answer
curl --request POST \
--url https://api.novita.ai/v3/exa/answer \
--header 'Authorization: <authorization>' \
--header 'Content-Type: <content-type>' \
--data '
{
"query": "<string>",
"text": true,
"outputSchema": {
"type": "<string>",
"properties": {},
"required": [
"<string>"
],
"description": "<string>",
"additionalProperties": {}
}
}
'import requests
url = "https://api.novita.ai/v3/exa/answer"
payload = {
"query": "<string>",
"text": True,
"outputSchema": {
"type": "<string>",
"properties": {},
"required": ["<string>"],
"description": "<string>",
"additionalProperties": {}
}
}
headers = {
"Content-Type": "<content-type>",
"Authorization": "<authorization>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': '<content-type>', Authorization: '<authorization>'},
body: JSON.stringify({
query: '<string>',
text: true,
outputSchema: {
type: '<string>',
properties: {},
required: ['<string>'],
description: '<string>',
additionalProperties: {}
}
})
};
fetch('https://api.novita.ai/v3/exa/answer', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.novita.ai/v3/exa/answer",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'query' => '<string>',
'text' => true,
'outputSchema' => [
'type' => '<string>',
'properties' => [
],
'required' => [
'<string>'
],
'description' => '<string>',
'additionalProperties' => [
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: <content-type>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.novita.ai/v3/exa/answer"
payload := strings.NewReader("{\n \"query\": \"<string>\",\n \"text\": true,\n \"outputSchema\": {\n \"type\": \"<string>\",\n \"properties\": {},\n \"required\": [\n \"<string>\"\n ],\n \"description\": \"<string>\",\n \"additionalProperties\": {}\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "<content-type>")
req.Header.Add("Authorization", "<authorization>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.novita.ai/v3/exa/answer")
.header("Content-Type", "<content-type>")
.header("Authorization", "<authorization>")
.body("{\n \"query\": \"<string>\",\n \"text\": true,\n \"outputSchema\": {\n \"type\": \"<string>\",\n \"properties\": {},\n \"required\": [\n \"<string>\"\n ],\n \"description\": \"<string>\",\n \"additionalProperties\": {}\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.novita.ai/v3/exa/answer")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = '<content-type>'
request["Authorization"] = '<authorization>'
request.body = "{\n \"query\": \"<string>\",\n \"text\": true,\n \"outputSchema\": {\n \"type\": \"<string>\",\n \"properties\": {},\n \"required\": [\n \"<string>\"\n ],\n \"description\": \"<string>\",\n \"additionalProperties\": {}\n }\n}"
response = http.request(request)
puts response.read_body{
"requestId": "string",
"answer": "string",
"citations": [
{
"id": "string",
"title": "string",
"url": "string",
"publishedDate": "string",
"author": "string",
"text": "string"
}
]
}
{
"code": 400,
"reason": "INVALID_REQUEST_BODY",
"message": "Invalid request body | Validation error: expected string, received undefined at \"query\"",
"metadata": {
"trace_id": "0748a32faccde3d924752336fd5c1a31"
}
}
{
"code": 403,
"reason": "INVALID_API_KEY",
"message": "invalid api-key",
"metadata": {}
}
{
"code": 404,
"reason": "PATH_NOT_FOUND",
"message": "path not found for model",
"metadata": {
"trace_id": "3c3433f0cb475a04f9a4969b8c6ed903"
}
}
{
"code": 429,
"reason": "RATE_LIMIT_EXCEEDED",
"message": "rate limit exceeded, please retry later",
"metadata": {
"trace_id": "5f2a9c7e41b8d0a36e9f4c2b7d81a0e5"
}
}
{
"code": 500,
"reason": "TASK_FAILED",
"message": "upstream provider temporarily unavailable, please retry",
"metadata": {
"trace_id": "8846379c692d7218173460afe95640f1"
}
}
{
"code": 503,
"reason": "SERVICE_UNAVAILABLE",
"message": "service temporarily unavailable",
"metadata": {
"trace_id": "b7e3f1a9d24c05e8f63a1b9c7e05d2f4"
}
}
Generate an answer to a question using Exa search results, with optional citations and source text. This is a passthrough to Exa’s Answer API, exposed through the Novita gateway with a platform route prefix.
To authenticate with your Novita API key, get one from the Novita dashboard. Base URL:
Running the quickstart above returns the following. The request returned 8 citations; three are shown here.
For validation failures,
https://api.novita.ai.
Quickstart
curl -X POST 'https://api.novita.ai/v3/exa/answer' \
-H 'Authorization: Bearer <api_key>' \
-H 'Content-Type: application/json' \
-d '{
"query": "How tall is the Burj Khalifa?"
}'
{
"requestId": "50bd53d7599d1415761aaefea608f113",
"answer": "The Burj Khalifa has a roof height of 828 meters (2,717 feet) [1][2][3]. When measured to the tip of its antenna, the total height is 829.8 meters (2,722 to 2,723 feet) [1][2][4].",
"citations": [
{
"id": "https://en.wikipedia.org/wiki/Burj_Khalifa",
"title": "Burj Khalifa - Wikipedia",
"url": "https://en.wikipedia.org/wiki/Burj_Khalifa",
"publishedDate": "2026-05-31T00:00:00.000Z"
},
{
"id": "https://www.skyscrapercenter.com/building/burj-khalifa/3",
"title": "Burj Khalifa - The Skyscraper Center",
"url": "https://www.skyscrapercenter.com/building/burj-khalifa/3"
},
{
"id": "https://www.britannica.com/topic/Burj-Khalifa",
"title": "Burj Khalifa | Height, Architect, Top Floor, & Facts | Britannica",
"url": "https://www.britannica.com/topic/Burj-Khalifa"
}
]
}
Request Headers
All endpoints require platform API authentication.string
required
Use
application/json.string
default:"Bearer YOUR_API_KEY"
required
Platform API key, formatted as
Bearer YOUR_API_KEY.Request Body
string
required
Natural-language question or instruction. Minimum length is 1.
boolean
Whether to return source page text. Default is
false.object
JSON Schema Draft 7 object for structured answer output.
Show outputSchema properties
Show outputSchema properties
Examples
Basic answer
curl -X POST 'https://api.novita.ai/v3/exa/answer' \
-H 'Authorization: Bearer <api_key>' \
-H 'Content-Type: application/json' \
-d '{
"query": "What year was the Eiffel Tower completed?",
"text": true
}'
Structured answer
curl -X POST 'https://api.novita.ai/v3/exa/answer' \
-H 'Authorization: Bearer <api_key>' \
-H 'Content-Type: application/json' \
-d '{
"query": "How tall is Mount Everest and where is it located?",
"outputSchema": {
"type": "object",
"properties": {
"heightMeters": {"type": "number"},
"country": {"type": "string"}
},
"required": ["heightMeters"]
}
}'
Answer with source text
Settext: true to return the full source text alongside each citation, useful when you want to display or re-verify the evidence.
curl -X POST 'https://api.novita.ai/v3/exa/answer' \
-H 'Authorization: Bearer <api_key>' \
-H 'Content-Type: application/json' \
-d '{
"query": "What are the main causes of coral bleaching?",
"text": true
}'
List-shaped structured answer
AnoutputSchema can return an array when you expect several items rather than a single fact.
curl -X POST 'https://api.novita.ai/v3/exa/answer' \
-H 'Authorization: Bearer <api_key>' \
-H 'Content-Type: application/json' \
-d '{
"query": "Which countries border Switzerland?",
"outputSchema": {
"type": "object",
"properties": {
"countries": {
"type": "array",
"items": {"type": "string"}
}
},
"required": ["countries"]
}
}'
Response
string
Unique request identifier.
string | object
Generated answer. It can be structured according to the
outputSchema provided in the request.object[]
Errors
Errors are returned as a JSON envelope withcode, reason, message, and metadata. The platform validates and authenticates the request before forwarding it to Exa, so some errors originate at the platform and others are surfaced from upstream.
| Status | reason | Meaning |
|---|---|---|
400 | MISSING_API_KEY | The Authorization header is absent. |
400 | INVALID_REQUEST_BODY | The body failed validation, such as a missing or malformed query. |
403 | INVALID_API_KEY | The API key is invalid or not authorized. |
404 | PATH_NOT_FOUND | The route does not exist. |
429 | RATE_LIMIT_EXCEEDED | Too many requests. Slow down and retry with backoff. |
500 | TASK_FAILED | Internal or upstream provider failure. Transient failures are safe to retry. |
503 | SERVICE_UNAVAILABLE | The service is temporarily overloaded or down. Retry with backoff. |
message is a JSON-encoded string carrying the detailed error and tag. The examples below show that inner detail decoded for readability.
{
"requestId": "string",
"answer": "string",
"citations": [
{
"id": "string",
"title": "string",
"url": "string",
"publishedDate": "string",
"author": "string",
"text": "string"
}
]
}
{
"code": 400,
"reason": "INVALID_REQUEST_BODY",
"message": "Invalid request body | Validation error: expected string, received undefined at \"query\"",
"metadata": {
"trace_id": "0748a32faccde3d924752336fd5c1a31"
}
}
{
"code": 403,
"reason": "INVALID_API_KEY",
"message": "invalid api-key",
"metadata": {}
}
{
"code": 404,
"reason": "PATH_NOT_FOUND",
"message": "path not found for model",
"metadata": {
"trace_id": "3c3433f0cb475a04f9a4969b8c6ed903"
}
}
{
"code": 429,
"reason": "RATE_LIMIT_EXCEEDED",
"message": "rate limit exceeded, please retry later",
"metadata": {
"trace_id": "5f2a9c7e41b8d0a36e9f4c2b7d81a0e5"
}
}
{
"code": 500,
"reason": "TASK_FAILED",
"message": "upstream provider temporarily unavailable, please retry",
"metadata": {
"trace_id": "8846379c692d7218173460afe95640f1"
}
}
{
"code": 503,
"reason": "SERVICE_UNAVAILABLE",
"message": "service temporarily unavailable",
"metadata": {
"trace_id": "b7e3f1a9d24c05e8f63a1b9c7e05d2f4"
}
}
Notes
- All request bodies are JSON.
- Extra Exa parameters not listed here may be passed through.
- Response shapes can vary depending on request options.
- This document intentionally omits billing-related fields.
References
For more details, see the Exa Answer API reference.Last modified on July 30, 2026
Was this page helpful?
⌘I