Cookbook

Submit an advice record

POST a piece of advice into the Principal review queue, with model provenance, vulnerability flags, and metadata.

The shape of the request

ts
type VulnerabilityFlag = 'health' | 'life_event' | 'capability' | 'resilience';

type SubmitInput = {
  // Required
  documentUrl: string;          // URL Bedrock can fetch the source document from
  documentType: string;         // e.g. "SUITABILITY_REPORT"
  clientReference: string;      // your stable client identifier
  documentReference: string;    // your stable document identifier
  factFindSummary: Record<string, unknown>; // structured summary of the client fact find

  // Optional
  priority?: 'STANDARD' | 'URGENT';
  modelProvider?: string;       // e.g. "openai" — feeds the model registry
  modelVersion?: string;        // e.g. "gpt-4o-2024-08-06"
  modelConfiguration?: Record<string, unknown>; // inference parameters (temperature, top_p, etc.)

  // FG21/1 vulnerability routing — any non-empty array forces
  // requiresSeniorSignOff: true and restricts the job to specialist
  // reviewers. See /docs/features/vulnerability-routing.
  vulnerabilityFlags?: VulnerabilityFlag[];
  requiresSeniorSignOff?: boolean;

  // Anonymised categorical segments for bias / fairness monitoring.
  // Values are plain strings and aggregated across jobs on the
  // /v1/firm/me/bias report — pick categorical labels rather than
  // identifiers. See /docs/features/bias-monitoring.
  clientSegments?: Record<string, string>;
};

A complete TypeScript example

ts
import { request } from 'undici';

export async function submitAdvice(input: SubmitInput) {
  const res = await request('https://api.bedrockcompliance.co.uk/v1/principal/jobs', {
    method: 'POST',
    headers: {
      'X-Bedrock-Key': process.env.BEDROCK_API_KEY!,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(input),
  });

  if (res.statusCode === 403) {
    throw new Error('Plan insufficient for principal services.');
  }
  if (res.statusCode === 422) {
    throw new Error('Document download failed — check that documentUrl is reachable from Bedrock.');
  }
  if (res.statusCode !== 201) {
    throw new Error(`Bedrock submit failed: ${res.statusCode}`);
  }
  return (await res.body.json()) as {
    id: string;
    status: 'QUEUED' | 'ASSIGNED' | 'IN_REVIEW' | 'COMPLETED';
  };
}

Calling it

ts
const job = await submitAdvice({
  documentType: 'SUITABILITY_REPORT',
  documentUrl: 'https://files.example.com/suitability-12345.pdf',
  clientReference: 'client-12345',
  documentReference: 'suitability-12345',
  factFindSummary: {
    adviser: 'Jane Smith',
    product: 'Stocks & Shares ISA',
    fundsValue: 25000,
  },
  priority: 'STANDARD',
  modelProvider: 'openai',
  modelVersion: 'gpt-4o-2024-08-06',
  modelConfiguration: { temperature: 0.2, topP: 0.95 },
  vulnerabilityFlags: ['health', 'life_event'], // routed to a specialist
  clientSegments: {
    ageBand: '65+',
    riskProfile: 'Cautious',
    productType: 'SIPP',
  },
});

console.log('Submitted as', job.id);

Common gotchas

  • The documentUrl must be reachable from Bedrock. Presigned S3 URLs work well; URLs behind a VPN do not. A failed fetch returns 422.
  • Pin modelVersion to an exact version, not a moving alias. Drift detection only works against pinned versions.
  • Set clientReference and documentReference to stable values. They are how you join Bedrock data back to your customer and document records later.

See also