Adaptive Retrieval
API Guide

API Guide

Adaptive Retrieval offers a single endpoint to retrieve relevant data across any number of S&P datasets using natural language. Data is returned directly from S&P databases, with citations, mitigating risks of LLM hallucinations and giving users an auditability trail to have confidence in responses.

Endpoint

POST https://grounding.kensho.com/api/v2/search

Authentication

The production environment uses S&P Global Okta for authentication. There are two ways to obtain an access token:

Browser Login (Interactive Users)

  1. Go to https://grounding.kensho.com/login-spgi (opens in a new tab) and follow the instructions until you reach a page displaying "Logged in as <your email>".
  2. Copy the access token displayed on the page. The access token is valid for 1 hour before you need to log in again to renew it.
  3. Use the access token as Bearer authentication in your API requests.

Keypair Authentication (Service Accounts)

For programmatic access, use the OAuth 2.0 private_key_jwt client credentials flow with your S&P Global client ID and private key.

This method uses a signed JWT assertion (per RFC 7523 (opens in a new tab)). You will need:

  • Your client ID (provided during service account provisioning)
  • Your RSA private key in PEM format (the corresponding public key is registered with S&P Global during provisioning)

Generate Your Keypair

Generate an RSA keypair using OpenSSL:

# Generate a 2048-bit RSA private key
openssl genrsa -out private_key.pem 2048
 
# Extract the public key
openssl rsa -in private_key.pem -pubout -out public_key.pem

Keep your private key (private_key.pem) secure — you will use it to sign authentication requests. Do not share it.

Send your public key (public_key.pem) to support.datafeed.mi@spglobal.com to have it registered with your service account. Once provisioned, you will receive a client ID to use with the authentication flow below.

Dependencies

pip install PyJWT cryptography requests

Get an Access Token

import time
 
import jwt
import requests
 
# ──────────────────────────────────────────────────────────────────────────────
# Fill in your credentials below
# ──────────────────────────────────────────────────────────────────────────────
CLIENT_ID = "YOUR_CLIENT_ID"
PRIVATE_KEY_PATH = "/path/to/your/private_key.pem"
# ──────────────────────────────────────────────────────────────────────────────
 
TOKEN_URL = "https://secure.signin.spglobal.com/oauth2/spglobal/v1/token"
SCOPE = "api:kensho_grounding"
 
# Read your private key
with open(PRIVATE_KEY_PATH, "rb") as f:
    private_key = f.read()
 
# Build the signed JWT client assertion (RFC 7523)
iat = int(time.time())
claims = {
    "iss": CLIENT_ID,
    "sub": CLIENT_ID,
    "aud": TOKEN_URL,
    "iat": iat,
    "exp": iat + 30 * 60,  # valid for 30 minutes
}
client_assertion = jwt.encode(claims, private_key, algorithm="RS256")
 
# Request the access token
response = requests.post(
    TOKEN_URL,
    data={
        "grant_type": "client_credentials",
        "scope": SCOPE,
        "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
        "client_assertion": client_assertion,
    },
)
response.raise_for_status()
 
token = response.json()["access_token"]
print(f"Access token (expires in {response.json()['expires_in']}s):\n{token}")

The response will contain an access_token field. Tokens are valid for 1 hour.

Code Examples

import requests
 
url = "https://grounding.kensho.com/api/v2/search"
headers = {
    "Authorization": "Bearer YOUR_TOKEN_HERE",
    "Content-Type": "application/json"
}
data = {
    "query": "What is Apple's P/E ratio?"
}
response = requests.post(url, json=data, headers=headers)
 
print(response.status_code)  # verify this is 200
print(response.json())

Request Parameters

ParameterTypeRequiredDescription
querystringYesThe natural language query to search for data
allowed_datasetslist[string]NoOptional list of specific data agent names to query. If not provided, all available data agents will be queried. Valid agent names are returned from the agents endpoint (opens in a new tab).

Response Format

The API returns a JSON response with the following structure:

{
    "schema_version": "2.0",
    "response": [...]
}

Schema Version

The schema_version field indicates the version of the response schema being used. The current latest version is "2.0".

Response Data

The response array contains the results of your query. Each item represents a table of data with rich metadata:

{
  "representation_type": "tabular",
  "schema": {
    "fields": [
      {"name": "column1", "type": "string"},
      {"name": "column2", "type": "integer"},
      {"name": "column3", "type": ["number", "null"]}
    ]
  },
  "data": [
    {"column1": "value1", "column2": 42, "column3": 3.14},
    {"column1": "value2", "column2": 84, "column3": null}
  ],
  "sources": [
    {
      "type": "table",
      "source": {
        "uri": "https://example.com/source",
        "name": "Source Name",
        "provider": "S&P Global"
      }
    },
    {
      "type": "cell",
      "row": 0,
      "column": "column1",
      "source": {
        "uri": "https://example.com/specific-source",
        "name": "Specific Cell Source",
        "provider": "S&P Global"
      }
    }
  ],
  "problems": [],
  "metadata": {}
}

Tabular Data Structure

  • schema.fields: Array of column definitions with names and types
  • data: Array of row objects where each row is a dictionary with column names as keys
  • sources: Array of source attributions at table, row, column, or cell level

Source Information

Each source in the sources array provides detailed attribution:

{
  "type": "table|row|column|cell",
  "source": {
    "uri": "https://example.com/source-link",
    "name": "Human-readable source name",
    "provider": "Data provider name"
  },
  "index": 0,
  "name": "col_name",
  "row": 0,
  "column": "col_name"
}

Schema Types

The v2 format uses JSON Schema primitive types for column definitions:

  • "null": Null values only
  • "boolean": True/false values
  • "integer": Whole numbers
  • "number": Integers and floating-point numbers
  • "string": Text values

Columns can accept multiple types by using an array format:

  • ["string", "null"]: String values that can also be null
  • ["integer", "number", "null"]: Numeric values that can be null

Problems

Each result has a problems array that contains any actionable issues encountered during data retrieval.

Response Headers

Each API response includes headers to help you monitor your usage:

HeaderDescription
x-usage-remainingThe number of requests remaining in your current usage period
x-usage-limitThe total number of requests allowed in your current usage period

Error Handling

The API uses standard HTTP status codes along with detailed problem descriptions in the response body.

Authentication Errors

  • 401 Unauthorized: Authentication token is missing or invalid. You need to log in again to get a new access token.
  • 403 Forbidden: Your token is valid but you don't have permission to access the requested resource.

Access Token Expiration

Access tokens expire after 1 hour. When your token expires, you'll receive a 401 Unauthorized response. To get a new token, visit https://grounding.kensho.com/login-spgi (opens in a new tab) again or use the keypair authentication flow to obtain a new token programmatically.

Request Errors

  • 400 Bad Request: The request was malformed or contained invalid parameters.
  • 422 Unprocessable Entity: The request was well-formed but contained semantic errors.

Server Errors

  • 500 Internal Server Error: Something went wrong on the server.
  • 503 Service Unavailable: The service is temporarily unavailable or overloaded.