The Value of Response Shaping
One of our absolute favorite features of Tango is "response shaping."
Response shaping means requesting only the fields you need from the API instead of pulling all the fields all the time. Federal procurement data, for a variety of reasons, is notably wide: records have dozens, sometimes hundreds of fields, with nested objects (recipients, place of performance, etc.). Because most federal procurement APIs always return everything, response times are usually large, and slow.
With response shaping on Tango, however you can pass a shape parameter directly in the URL query that describes which fields you want (including nested ones), and the API will return only those fields.
In this post we'll cover why response shaping matters, how to use it via the API or the tango-python and tango-node SDKs, and concrete use cases so you can decide when it's worth it.
Why response shaping matters
Many APIs return full resources by default: every field on every record. Suppose, though, you only need a few fields from each record (piid, award_date, description, recipient(display_name), and total_contract_value) in a list view. Most of the time, you still get the whole object.
That means:
- Larger payloads — More data over the wire, slower responses, and more memory and CPU to parse. When you're listing dozens or hundreds of records, the difference adds up.
- Wasted tokens — If you feed API responses to an LLM for summarization or RAG, you pay for every token. Sending full objects when you only need a handful of fields means you're paying for fields the model never uses. And worse, extra context runs the risk of LLMs misunderstanding or misapplying the data.
- Noisier code — You end up ignoring or plucking fields on the client. Simpler to ask for what you need and get it.
Response shaping, drawing on principles from GraphQL and REST patterns like sparse fieldsets in JSON:API, flips the paradigm: you describe the shape you want and the API returns only those fields.
Often, that can be as much as 60–80% smaller payloads without changing the API contract. You get faster responses, lower bandwidth, and leaner payloads for LLMs. And your code stays simple because the response already matches what you need.
How Tango does response shaping
In Tango, to use response shaping, you simply pass shape as a query parameter (HTTP) or as an argument (SDKs). The API will then return only the fields you requested. Let's see some examples.
HTTP / REST
Pass shape as a query parameter on list endpoints. Include your API key in the X-API-KEY header (e.g. from an environment variable).
curl -G 'https://tango.makegov.com/api/contracts/' \
-H "X-API-KEY: ${TANGO_API_KEY}" \
--data-urlencode "shape=key,piid,description,recipient(*),total_contract_value" \
--data-urlencode "limit=10"
The response contains only the requested fields. The same shape parameter works on other list endpoints (e.g. /api/opportunities/, /api/entities/) and with any HTTP client.
Python (SDK): (use TANGO_API_KEY in your environment)
import os
from tango import TangoClient
client = TangoClient(api_key=os.environ["TANGO_API_KEY"])
contracts = client.list_contracts(
shape="key,piid,recipient(*),total_contract_value",
limit=10
)
for contract in contracts.results:
print(contract["piid"], contract["recipient"]["display_name"])
Node/TypeScript: (use TANGO_API_KEY in your environment)
import { TangoClient, ShapeConfig } from "@makegov/tango-node";
const client = new TangoClient({ apiKey: process.env.TANGO_API_KEY });
const contracts = await client.listContracts({
shape: ShapeConfig.CONTRACTS_MINIMAL,
limit: 10,
});
for (const c of contracts.results) {
console.log(c.piid, c.recipient.display_name);
}
You can use predefined shapes (e.g. ShapeConfig.CONTRACTS_MINIMAL) or custom strings like "key,piid,award_date,recipient(display_name)". The SDKs also give you types derived from your shape—TypedDicts in Python, TypeScript types in Node—so you get smaller payloads and better type safety together.
So: REST = add shape to the query string; SDKs = pass shape to the list method. Same API, same shape syntax.
Use cases
Here are concrete ways response shaping helps:
- List views and dashboards — When you're showing a table of contracts (with columns like
piid,date,description,recipient,total_contract_value), you don't need all the data, such as place of performance, transactions, or 20 other fields. Request only the columns you display and get a much smaller response. Faster load, less parsing. - LLM and AI pipelines — When you feed contract or opportunity data to an LLM for summarization or RAG, you pay for tokens on every field. Requesting only the fields relevant to the prompt (e.g. title, description, due date) keeps payloads small and token cost down. No need to send full objects and trim on your side.
- Data pipelines and ETL — When you're syncing a subset of fields to a warehouse or another system, request only those fields. Smaller transfers, simpler mapping, and less redundant data.
- Mobile and bandwidth-sensitive clients — When every byte counts, response shaping reduces payload size without changing how you call the API. Same filters and pagination; only the response body shrinks.
In all of these, the pattern is the same: you pass a shape and the API returns only those fields.
If you're building on the Tango API and care about payload size and token cost, response shaping is a really useful feature that you should almost certainly be using. For the full reference on response shaping, check out our response-shaping guide.
And remember, Tango has a free tier. So, if you want to try it out, go ahead and sign up today!
Ready to Get Started with Tango?
If you're working with federal procurement data, Tango provides a unified API that combines federal procurement data sets, improves on them, with a developer-friendly approach. Skip the complexity of scraping and joining multiple government APIs yourself.