
How do agents retrieve brand context at runtime?
Retrieve task-specific brand guidance and files, pass them to the tools making the work, and record the version used. Implement deliberate reuse and a visible failure path.
TL;DR
Retrieve brand context before the step that creates branded work. Identify the intended brand, describe the task, wait for usable guidance and files, then pass them to the producing tools. Record the version used. Reuse context only while the task and relevant brand inputs still fit, and make retrieval failures visible instead of silently producing generic work.
Fetch the context before creating the work
Fetch the relevant rules and files before calling the creation model or renderer. Retrieval is only useful if those inputs reach the tool making the output.
Your application can fetch them before invoking a model, or the agent can request them during the task:
| Retrieval point | Who initiates it | What to make explicit |
|---|---|---|
| Application step before generation | Your code | The fetch must complete before creation starts |
| Agent tool call during the task | The model, following its instructions | When to call, what to request and what to do if it fails |
| Local snapshot read during the task | The agent or application | Which version is installed and when to replace it |
Anthropic describes retrieving context as needed; OpenAI shows how a model requests a tool call and your application runs it. A local snapshot stays at its installed version.
Keep retrieval instructions separate from brand details
Keep changing brand details in maintained context. Standing instructions should cover:
- Which brand to use, and how to resolve an ambiguous request.
- Which tasks need brand context.
- How to pass the guidance and files to the tools making the output.
- What to report when retrieval fails or the guidance does not cover the task.
For customer-facing products, resolve the authorised Brand ID on your server; do not let the model guess from a name. Supply the task's format, dimensions, audience, channel, copy and constraints. Keep temporary offers or creative directions distinct from established brand facts.
Request and wait for usable context
Rainbrand maintains brand context for agents and products. A Brief selects guidance and files for the supplied Brand ID and task.
- MCP (Model Context Protocol): call
create_brief, thenget_briefwith itsbrief_idandwait: true. Repeat while pending or processing. - REST: set your API key, replace the placeholder with an accessible ready brand, and supply your task:
curl --request POST https://www.rainbrand.com/api/v1/briefs \
--header "x-api-key: $RAINBRAND_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"brandSessionId": "<YOUR_BRAND_ID>",
"task": "A 1600 × 900 campaign image for [brand], aimed at [audience]. Use the headline [exact headline] and call to action [exact copy]."
}'
Read GET /briefs/{id}?wait=true with the returned data.id and the same authentication. Poll while pending or processing; use only a completed result. A failed result supplies error and retry details.
The create request returns HTTP 202 with this documented response:
{
"data": {
"id": "<RETURNED_BRIEF_ID>",
"status": "pending"
}
}
For Node.js 20+, save this as request-brief.mjs; it uses built-in fetch. Set RAINBRAND_API_KEY, RAINBRAND_BRAND_ID and RAINBRAND_REQUEST_KEY, replace the task, and run node request-brief.mjs. Retain a unique request key per task; reuse it only to recover the same POST and body.
import { setTimeout as delay } from "node:timers/promises";
const apiKey = process.env.RAINBRAND_API_KEY;
const brandId = process.env.RAINBRAND_BRAND_ID;
const requestKey = process.env.RAINBRAND_REQUEST_KEY;
if (!apiKey || !brandId || !requestKey) {
throw new Error("Set the API key, authorised Brand ID and request key");
}
const task =
"A 1600 × 900 campaign image for [brand], aimed at [audience]. " +
"Use the headline [exact headline] and call to action [exact copy].";
const baseUrl = "https://www.rainbrand.com/api/v1";
const deadline = Date.now() + 5 * 60_000;
async function request(path, options = {}) {
for (let attempt = 0; attempt < 3; attempt++) {
const remaining = deadline - Date.now();
if (remaining <= 0) throw new Error("Brief wait budget exhausted");
const response = await fetch(`${baseUrl}${path}`, {
...options,
headers: {
"x-api-key": apiKey,
"Content-Type": "application/json",
...options.headers,
},
signal: AbortSignal.timeout(Math.min(30_000, remaining)),
});
const body = await response.json();
if (response.status === 429 && attempt < 2) {
const header = response.headers.get("Retry-After");
const seconds = header === null ? NaN : Number(header);
const waitMs =
Number.isFinite(seconds) && seconds >= 0
? Math.max(1_000, seconds * 1_000)
: 1_000 * 2 ** attempt;
if (waitMs < deadline - Date.now()) {
await delay(waitMs);
continue;
}
}
if (!response.ok) {
throw new Error(
`${response.status}: ${body.error?.message ?? "Request failed"}`
);
}
if (!body.data) throw new Error("Response has no data");
return body.data;
}
}
async function main() {
const created = await request("/briefs", {
method: "POST",
headers: { "idempotency-key": requestKey },
body: JSON.stringify({ brandSessionId: brandId, task }),
});
if (!created.id) throw new Error("No Brief ID returned");
console.error(`Brief ID: ${created.id}`);
while (Date.now() < deadline) {
const brief = await request(
`/briefs/${encodeURIComponent(created.id)}?wait=true&timeout=20`
);
if (brief.status === "pending" || brief.status === "processing") {
await delay(1_000);
continue;
}
if (brief.status === "failed") {
throw new Error(
`${brief.error?.code ?? "BRIEF_FAILED"}: ` +
`${brief.error?.message ?? "Brief failed"}; ` +
`new attempt may succeed: ${brief.error?.retryable === true}`
);
}
if (
brief.status !== "completed" ||
!brief.skillId ||
typeof brief.guidance !== "string" ||
!brief.guidance.trim() ||
!Array.isArray(brief.assets)
) {
throw new Error("Brief has no usable completed context");
}
// This is the input record for your producing tools.
console.log(
JSON.stringify(
{
brandId,
briefId: brief.id,
skillId: brief.skillId,
task,
guidance: brief.guidance,
assets: brief.assets,
},
null,
2
)
);
return;
}
throw new Error("Wait budget exhausted; resume reading the saved Brief ID");
}
await main().catch((error) => {
console.error(error.message);
process.exitCode = 1;
});
The example's failure handling is deliberate:
- Five minutes overall and up to three attempts per rate-limited request are workflow choices.
- Numeric
Retry-Afterdelays have a one-second minimum. Otherwise retries wait one then two seconds; a delay beyond the remaining budget stops the request. - Other HTTP errors, network failures, unavailable versions and unusable/failed results stop the script. Pending work keeps the same Brief.
- Retain the key and Brief ID to recover the POST or resume reading. A new attempt after terminal failure needs a new key.
The API quickstart covers this sequence, and Get a Brief defines the response:
| REST field | Use |
|---|---|
data.id | Save the Brief reference with the output |
data.skillId | Record the brand version used; it can be null if that version was deleted |
data.guidance | Pass the completed Markdown guidance to the producing step |
data.assets | Route the selected files by their kind, media type and URL |
data.error | Inspect failure details rather than treating a failed Brief as empty guidance |
Pass both guidance and files to the producing tools
Keep the task, guidance and files together. Renderers need actual font and logo files; image models may also need references and type specimens.
For banking platform Mercury, Codex built a payment-confirmation concept using the Brief's downloaded Arcadia fonts and original logo:

Codex rendered the screen with the supplied logo and font files
Pass supported inputs to your creation tools. If a format is unsupported, use a suitable renderer rather than silently dropping it. For a connected agent:
For [brand] work, request a Rainbrand Brief describing the output, audience, channel and exact copy. Wait for completion and inspect the guidance and files. Give the original task, guidance and relevant assets to each tool creating the work. Use the supplied logo and fonts where the tool supports them. If the guidance does not fit, correct the task and request another Brief. If retrieval fails or a required file cannot be used, report it before continuing.For the complete brand locally, export a Brand Skill: saved identity, guidance and assets. Keep the folder structure and version, and replace it after relevant changes.
Reuse by task and version
The Brief tools recommend reuse for the same goal, audience, direction and sources. Before reuse:
- Check access to the intended brand.
- Check its version. Compare
data.activeSkill.idwith the Brief'sdata.skillId. If different or missing, retrieve fresh context. - Check task and assets. Direct Library changes can require refresh too. Removal affects future Briefs, not completed ones.
- Open required files before handing them to creation tools.
Preserve original inputs with historical work. Cache expiry alone does not establish freshness, and an edit after your version check can still leave the task on earlier guidance; record what it actually used.
Requests use credits, so reuse closely related context instead of requesting it for every message.
Distinguish context reuse from prompt caching
A provider's prompt cache reuses processing for matching input; it does not fetch today's brand. OpenAI recommends stable material first and changing content later. Keep standing instructions stable, then supply retrieved context in messages or tool results.
File access has its own lifetime:
| Context | File links |
|---|---|
| Completed Brief | No scheduled expiry while the Brief, brand, version and asset remain available. Anyone holding a link can open it. |
| Retrieved Brand Skill | Temporary signed URLs. Retrieve again after expiry and check the returned brand version. |
Make failure visible before generation
Stop creation when required context is missing:
| Failure | Response |
|---|---|
| Wrong or ambiguous brand | Resolve the intended accessible brand before requesting context |
| Brief still pending | Continue reading the same Brief |
| Brief failed | Read its error; retry only when appropriate and within your retry budget |
| Missing permission | Correct access instead of using another customer's or a default brand |
| Rate limit | Wait for the returned delay before retrying |
| Required asset unavailable | Refresh access or report the missing input |
| Context omitted from a downstream tool | Repair the handoff and repeat the affected creation step |
Use bounded retries and Retry-After; record the failed stage. After creation, Review can check the finished image and expected copy against the brand. Your tools make corrections.
Verify the entire handoff
Inspect one record linking brand, Brief, version, inputs and output. Test unavailable retrieval, stale context and unreadable files; each should stop creation with a useful reason. The embedded-product guide covers the surrounding product workflow.
More in Developers
All 5 Developers articles8 min read
Best brand APIs for AI agents
Brand APIs return different things. Lookups describe any company’s public identity, platform APIs read the files a customer already stores, and a maintained brand returns guidance and files for each task. Compare what each returns, who keeps it current, how access works and how pricing differs.
5 min read
How to add brand context to your AI product
Follow a generation job from the customer’s task and authorized brand through guidance, assets, rendering and review. Keep future jobs current with saved brand versions and applied corrections.
6 min read
How to manage your customers’ brands in an AI product
Tie each customer to the right brand on your server, then handle creation, corrections, versions and deletion without exposing another customer's guidance or files.
