Guide
Audit Proxy
Capture a full audit log of every AI call — across any provider — with a one-line change to your existing code. Your provider keys stay yours; Flint never stores them.
How it works
Route your SDK through the Flint proxy by changing baseURL. Every request is forwarded verbatim to the real provider using the key you pass in x-provider-key. That key is used for the outbound call and immediately discarded — it is never written to a database, log, or any storage layer.
...k3f2) is saved in the audit record for reference.Setup
1. Get a Flint API key
Go to Settings → API Keys → Create key. Keys look like flnt_live_....
2. Change one line in your SDK
import OpenAI from 'openai';
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY, // your key — forwarded, never stored
baseURL: 'https://api.flintlogic.com/v1/proxy/openai',
defaultHeaders: {
'Authorization': `Bearer ${process.env.FLINT_API_KEY}`,
'x-provider-key': process.env.OPENAI_API_KEY,
},
});
// Everything else stays exactly the same
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: 'Summarise this contract in 3 bullets.' }],
});Client-side mode
If you'd prefer the AI call to stay entirely on your infrastructure — no traffic routed through Flint — make the call directly and report the result afterward via POST /audit/report. Flint receives only the audit data; the provider response never transits Flint's servers.
import OpenAI from 'openai';
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
async function chat(messages) {
const start = Date.now();
const response = await openai.chat.completions.create({ model: 'gpt-4o', messages });
const latencyMs = Date.now() - start;
// Fire-and-forget — does not block your response.
// Include 'messages' to enable prompt capture (Settings → Data & Privacy).
fetch('https://api.flintlogic.com/v1/audit/report', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.FLINT_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
provider: 'openai', endpoint: '/v1/chat/completions',
response, latencyMs, status: 200,
messages, // required for prompt capture
}),
}).catch(() => {});
return response;
}Report payload
| Field | Required | Description |
|---|---|---|
| provider | Yes | openai, anthropic, or gemini |
| endpoint | Yes | Provider API path, e.g. /v1/chat/completions |
| response | Yes | Raw provider response object — tokens and model extracted from this |
| latencyMs | No | Client-measured call duration in milliseconds |
| status | No | HTTP status code returned by the provider (default 200) |
| messages | No | Array of {role, content} — required for prompt capture to work in client-side mode |
| system | No | Anthropic system prompt string — included in prompt capture when provided |
source: "client" field to distinguish the two modes.Prompt capture
Enable Settings → Data & Privacy → Prompt capture to store prompt previews, SHA-256 hashes, and full prompt/completion content for each request. Off by default — only enable if your prompts contain no PII or confidential data.
| Mode | What you need to do |
|---|---|
| Proxy | Nothing — the proxy extracts the prompt automatically from the forwarded request body. |
| Client-side | Include messages (and system for Anthropic) in your /v1/audit/report payload. Without messages, the report is still recorded but prompt data is skipped. |
When capture is on, each audit record gains additional fields. A 100-character preview and hash are always stored in the audit record. The full prompt and completion are stored in S3 and retrievable via the API.
# Fetch the full prompt + completion stored in S3 for a specific request
curl "https://api.flintlogic.com/v1/audit/prompt/<requestId>" \
-H "Authorization: Bearer $FLINT_API_KEY"
# Response
{
"prompt": "Summarise this contract in 3 bullets.\n\nContract text...",
"completion": "1. Payment terms are net-30.\n2. ...",
"provider": "openai",
"model": "gpt-4o"
}Proxy base URLs
| Provider | Set as baseURL |
|---|---|
| OpenAI | https://api.flintlogic.com/v1/proxy/openai |
| Anthropic | https://api.flintlogic.com/v1/proxy/anthropic |
| Gemini (GenAI SDK) | https://api.flintlogic.com/v1/proxy/gemini |
| Gemini (OpenAI SDK) | https://api.flintlogic.com/v1/proxy/gemini/v1beta/openai |
Querying your audit log
Retrieve paginated audit records for your org. You can also view them in the Audit tab of this dashboard.
# All calls in May 2025
curl "https://api.flintlogic.com/v1/audit?from=2025-05-01&to=2025-05-31" \
-H "Authorization: Bearer $FLINT_API_KEY"
# Only OpenAI calls, newest 50
curl "https://api.flintlogic.com/v1/audit?provider=openai&limit=50" \
-H "Authorization: Bearer $FLINT_API_KEY"
# Paginate with cursor
curl "https://api.flintlogic.com/v1/audit?cursor=eyJwayI6..." \
-H "Authorization: Bearer $FLINT_API_KEY"Filter parameters
| Parameter | Type | Description |
|---|---|---|
| from | ISO 8601 | Start of time range, e.g. 2025-01-01 |
| to | ISO 8601 | End of time range |
| provider | string | openai, anthropic, or gemini |
| model | string | Model ID, e.g. gpt-4o |
| limit | number | Records per page, max 500 (default 100) |
| cursor | string | Pagination token from previous response |
Response
{
"records": [
{
"requestId": "abc-123",
"provider": "openai",
"model": "gpt-4o",
"endpoint": "/v1/chat/completions",
"inputTokens": 512,
"outputTokens": 128,
"totalTokens": 640,
"costUsd": 0.00832,
"latencyMs": 843,
"status": 200,
"keyHint": "...k3f2",
"createdAt": "2025-05-04T14:22:01.000Z"
}
],
"nextCursor": "eyJwayI6...",
"count": 1
}What's captured
| Field | Description |
|---|---|
| requestId | Unique ID for the call |
| provider | openai, anthropic, or gemini |
| model | Model ID extracted from the provider response |
| endpoint | Provider API path, e.g. /v1/chat/completions |
| inputTokens | Prompt tokens consumed |
| outputTokens | Completion tokens generated |
| totalTokens | Sum of input + output |
| costUsd | Estimated USD cost based on published pricing |
| latencyMs | Time from proxy receipt to provider response |
| status | HTTP status returned by the provider |
| keyHint | Last 4 characters of the key used, e.g. ...k3f2 |
| createdAt | ISO 8601 timestamp |
| promptPreview | (prompt capture) First 100 characters of the prompt |
| promptHash | (prompt capture) SHA-256 hash of the full prompt — use for deduplication |
| completionPreview | (prompt capture) First 100 characters of the completion, proxy mode only |
| promptS3Key | (prompt capture) S3 object key — fetch full content via GET /v1/audit/prompt/:requestId |
Error reference
| Error code | Status | Meaning |
|---|---|---|
| unknown_provider | 400 | Provider in the URL is not supported |
| missing_provider_key | 400 | x-provider-key header is absent |
| upstream_error | 502 | Provider returned an error or timed out |