Rgl8r Public API V1.0.0
Source: docs/api/openapi/rgl8r-public-api-v1.0.0.yaml
openapi: 3.1.0
info:
title: RGL8R Public API
version: 1.0.0
summary: Public API contract for integration-key clients and AI agents.
description: |
Versioned contract for the public integration surface used by no-code automations,
CI pipelines, and AI agents.
Included surfaces:
- Integration-key token exchange
- Async job polling
- SIMA screening queue + reporting
- Upload enqueue endpoints
Compatibility policy is defined in docs/api/public-api-contract-v1.md.
servers:
- url: https://api.rgl8r.com
description: Production
- url: https://rgl8r-staging-api.onrender.com
description: Staging
security:
- bearerAuth: []
tags:
- name: Auth
description: Authenticate integration-key clients and issue short-lived bearer tokens.
- name: Jobs
description: Poll asynchronous processing state across upload and screening workflows.
- name: Trade Screening
description: Run SIMA screening and retrieve outcomes, evidence, summaries, and exports.
- name: Uploads
description: Enqueue CSV/Excel files for trade, catalog, ship, order, and carrier workflows.
paths:
/api/auth/token/integration:
post:
tags: [Auth]
operationId: createIntegrationToken
summary: Start an integration session (API key to bearer token)
description: |
Use this endpoint as step 1 in every integration flow.
Exchange a valid integration key (`x-api-key`) for a short-lived JWT bearer token,
then call tenant endpoints with `Authorization: Bearer <token>`.
security:
- integrationKeyHeader: []
responses:
'200':
description: Token issued
content:
application/json:
schema:
$ref: '#/components/schemas/IntegrationTokenResponse'
examples:
success:
value:
access_token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
token_type: Bearer
expires_in: 3600
default_adapter: catalog-excel
'400':
$ref: '#/components/responses/MissingApiKeyError'
'401':
$ref: '#/components/responses/AuthError'
'429':
$ref: '#/components/responses/RateLimitedError'
'500':
$ref: '#/components/responses/InternalError'
/api/jobs:
get:
tags: [Jobs]
operationId: listJobs
summary: Monitor async jobs for the authenticated tenant
description: |
Use this endpoint to monitor queue activity after upload/screening enqueue calls.
Supports filtering by job type and status for dashboards, polling loops, and alerts.
parameters:
- name: type
in: query
description: |
Optional job type filter.
Public integrations should use `catalog_upload` for trade catalog jobs.
(Legacy `wayfair_upload` values may still appear in older data but are not part of this public contract.)
schema:
type: string
enum:
- ship_upload
- sima_validation
- catalog_upload
- order_upload
- carrier_agreement_upload
- notification_digest
- notification_event
- name: status
in: query
description: Optional status filter.
schema:
type: string
enum: [PENDING, PROCESSING, COMPLETED, FAILED]
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 50
- name: offset
in: query
schema:
type: integer
minimum: 0
default: 0
responses:
'200':
description: Job list
content:
application/json:
schema:
$ref: '#/components/schemas/JobsListResponse'
'400':
$ref: '#/components/responses/InvalidRequestError'
'401':
$ref: '#/components/responses/AuthError'
'429':
$ref: '#/components/responses/RateLimitedError'
'500':
$ref: '#/components/responses/InternalError'
/api/jobs/{id}:
get:
tags: [Jobs]
operationId: getJobById
summary: Get one async job by ID
description: |
Poll this endpoint until the job reaches a terminal state (`COMPLETED` or `FAILED`).
This is the canonical status endpoint for enqueue-based workflows.
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Job detail
content:
application/json:
schema:
$ref: '#/components/schemas/JobResponse'
'400':
$ref: '#/components/responses/InvalidRequestError'
'401':
$ref: '#/components/responses/AuthError'
'404':
$ref: '#/components/responses/NotFoundError'
'429':
$ref: '#/components/responses/RateLimitedError'
'500':
$ref: '#/components/responses/InternalError'
/api/sima/batch:
post:
tags: [Trade Screening]
operationId: enqueueSimaBatch
summary: Queue SIMA screening for catalog SKUs
description: |
Creates an async SIMA validation job for selected or all SKUs in the tenant catalog.
Use this as step 2 in the canonical screening flow.
`screeningAuthority` is optional:
- omitted or blank: defaults to CA in downstream workers
- provided: must normalize to `CA` or `US`
parameters:
- $ref: '#/components/parameters/IdempotencyKeyHeader'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SimaBatchRequest'
examples:
allSkus:
value:
skus: null
runPolicy: always
screeningAuthority: US
responses:
'202':
description: Job accepted
content:
application/json:
schema:
$ref: '#/components/schemas/JobAcceptedResponse'
'400':
$ref: '#/components/responses/InvalidRequestError'
'401':
$ref: '#/components/responses/AuthError'
'409':
$ref: '#/components/responses/ActionNotAllowedError'
'429':
$ref: '#/components/responses/RateLimitedError'
'500':
$ref: '#/components/responses/InternalError'
/api/sima/results:
get:
tags: [Trade Screening]
operationId: listSimaResults
summary: Retrieve SIMA outcomes with workflow filters
description: |
Returns screened SKU outcomes (`AT_RISK`, `NEEDS_REVIEW`, `CLEARED`) plus workflow state.
Use this for flagged queues, analyst review surfaces, and downstream automations.
parameters:
- name: outcome
in: query
schema:
type: string
enum: [AT_RISK, NEEDS_REVIEW, CLEARED]
- name: workflow
in: query
schema:
type: string
enum: [OPEN, OVERRIDDEN, ACCEPTED, DISMISSED]
- name: workflow_not
in: query
schema:
type: string
enum: [OPEN, OVERRIDDEN, ACCEPTED, DISMISSED]
- name: hs_in_scope
in: query
schema:
type: boolean
- name: is_stale
in: query
schema:
type: boolean
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 1000
default: 50
- name: offset
in: query
schema:
type: integer
minimum: 0
default: 0
- name: cursor
in: query
schema:
type: string
responses:
'200':
description: SIMA outcomes
content:
application/json:
schema:
$ref: '#/components/schemas/SimaResultsResponse'
'400':
$ref: '#/components/responses/InvalidRequestError'
'401':
$ref: '#/components/responses/AuthError'
'429':
$ref: '#/components/responses/RateLimitedError'
'500':
$ref: '#/components/responses/InternalError'
/api/sima/summary:
get:
tags: [Trade Screening]
operationId: getSimaSummary
summary: Get SIMA KPI summary counts
description: |
Returns aggregate KPI counts for SIMA outcomes and workflow buckets.
Use this endpoint to power dashboard cards and high-level risk rollups.
parameters:
- name: outcome
in: query
schema:
type: string
enum: [AT_RISK, NEEDS_REVIEW, CLEARED]
- name: workflow
in: query
schema:
type: string
enum: [OPEN, OVERRIDDEN, ACCEPTED, DISMISSED]
- name: workflow_not
in: query
schema:
type: string
enum: [OPEN, OVERRIDDEN, ACCEPTED, DISMISSED]
responses:
'200':
description: SIMA summary
content:
application/json:
schema:
$ref: '#/components/schemas/SimaSummaryResponse'
'400':
$ref: '#/components/responses/InvalidRequestError'
'401':
$ref: '#/components/responses/AuthError'
'429':
$ref: '#/components/responses/RateLimitedError'
'500':
$ref: '#/components/responses/InternalError'
/api/sima/results/{sku}/evidence:
get:
tags: [Trade Screening]
operationId: getSimaEvidenceBySku
summary: Explain one SKU screening decision
description: |
Returns detailed evidence for a SKU outcome, including classification context,
matched signals, and workflow/audit trail data used for analyst review.
parameters:
- name: sku
in: path
required: true
schema:
type: string
responses:
'200':
description: Evidence payload
content:
application/json:
schema:
$ref: '#/components/schemas/SimaEvidenceResponse'
'401':
$ref: '#/components/responses/AuthError'
'404':
$ref: '#/components/responses/NotFoundError'
'429':
$ref: '#/components/responses/RateLimitedError'
'500':
$ref: '#/components/responses/InternalError'
/api/sima/report:
get:
tags: [Trade Screening]
operationId: exportSimaReport
summary: Export SIMA report data (JSON or CSV)
description: |
Export SIMA outcomes for BI tools, spreadsheets, and downstream reconciliation.
Returns JSON by default or CSV when `format=csv`.
parameters:
- name: format
in: query
schema:
type: string
enum: [json, csv]
default: json
- name: filter
in: query
schema:
type: string
enum: [flagged, covered]
- name: status
in: query
schema:
type: string
responses:
'200':
description: Report export
content:
application/json:
schema:
$ref: '#/components/schemas/SimaReportJsonResponse'
text/csv:
schema:
type: string
'401':
$ref: '#/components/responses/AuthError'
'429':
$ref: '#/components/responses/RateLimitedError'
'500':
$ref: '#/components/responses/InternalError'
/api/upload:
post:
tags: [Uploads]
operationId: enqueueTradeUpload
summary: Upload a trade catalog file for async processing
description: |
Enqueues a trade catalog file and returns a job ID for async processing.
Use the returned `jobId` with `/api/jobs/{id}` until terminal status.
parameters:
- $ref: '#/components/parameters/IdempotencyKeyHeader'
requestBody:
required: true
content:
multipart/form-data:
schema:
$ref: '#/components/schemas/TradeUploadRequest'
responses:
'202':
description: Upload accepted
content:
application/json:
schema:
$ref: '#/components/schemas/UploadAcceptedResponse'
'400':
$ref: '#/components/responses/InvalidRequestError'
'401':
$ref: '#/components/responses/AuthError'
'409':
$ref: '#/components/responses/ActionNotAllowedError'
'429':
$ref: '#/components/responses/RateLimitedError'
'413':
$ref: '#/components/responses/FileTooLargeError'
'415':
$ref: '#/components/responses/InvalidFileFormatError'
'500':
$ref: '#/components/responses/InternalError'
/api/catalog/upload:
post:
tags: [Uploads]
operationId: enqueueCatalogUpload
summary: Upload a product catalog for screening pipelines
description: |
Enqueues product catalog ingestion and normalization.
Use this when your integration starts from SKU catalog files before SIMA screening.
parameters:
- $ref: '#/components/parameters/IdempotencyKeyHeader'
requestBody:
required: true
content:
multipart/form-data:
schema:
$ref: '#/components/schemas/CatalogUploadRequest'
responses:
'202':
description: Upload accepted
content:
application/json:
schema:
$ref: '#/components/schemas/CatalogUploadAcceptedResponse'
'400':
$ref: '#/components/responses/InvalidRequestError'
'401':
$ref: '#/components/responses/AuthError'
'409':
$ref: '#/components/responses/ActionNotAllowedError'
'429':
$ref: '#/components/responses/RateLimitedError'
'413':
$ref: '#/components/responses/FileTooLargeError'
'415':
$ref: '#/components/responses/InvalidFileFormatError'
'500':
$ref: '#/components/responses/InternalError'
/api/ship/upload:
post:
tags: [Uploads]
operationId: enqueueShipUpload
summary: Upload shipment/invoice CSV for freight audit
description: |
Enqueues shipment and invoice data for async freight-audit processing.
Optional `adapter_id` is used for integration-key adapter allowlist enforcement.
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required: [file]
properties:
file:
type: string
format: binary
adapter_id:
type: string
description: Optional adapter identifier for integration-key adapter allowlist checks.
responses:
'202':
description: Upload accepted
content:
application/json:
schema:
$ref: '#/components/schemas/ShipUploadAcceptedResponse'
'400':
$ref: '#/components/responses/InvalidRequestError'
'401':
$ref: '#/components/responses/AuthError'
'403':
$ref: '#/components/responses/AdapterNotAllowedError'
'409':
$ref: '#/components/responses/DuplicateUploadError'
'429':
$ref: '#/components/responses/RateLimitedError'
'413':
$ref: '#/components/responses/FileTooLargeError'
'415':
$ref: '#/components/responses/InvalidFileFormatError'
'500':
$ref: '#/components/responses/InternalError'
/api/orders/upload:
post:
tags: [Uploads]
operationId: enqueueOrdersUpload
summary: Upload order CSV for order-side enrichment/reconciliation
description: |
Enqueues order ingestion used by downstream shipment/order workflows.
`ingestMode` controls patch vs full-snapshot behavior.
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required: [file]
properties:
file:
type: string
format: binary
ingestMode:
type: string
enum: [PATCH, SNAPSHOT]
responses:
'202':
description: Upload accepted
content:
application/json:
schema:
$ref: '#/components/schemas/OrderUploadAcceptedResponse'
'400':
$ref: '#/components/responses/InvalidRequestError'
'401':
$ref: '#/components/responses/AuthError'
'409':
$ref: '#/components/responses/DuplicateUploadError'
'429':
$ref: '#/components/responses/RateLimitedError'
'413':
$ref: '#/components/responses/FileTooLargeError'
'415':
$ref: '#/components/responses/InvalidFileFormatError'
'500':
$ref: '#/components/responses/InternalError'
/api/carrier/agreements/upload:
post:
tags: [Uploads]
operationId: enqueueCarrierAgreementUpload
summary: Upload carrier agreement CSV for contract-rate checks
description: |
Enqueues carrier agreement ingestion used to validate billed rates against contract terms.
Requires `ship:upload` scope for integration principals.
x-rgl8r-required-scopes: ['ship:upload']
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required: [file]
properties:
file:
type: string
format: binary
responses:
'202':
description: Upload accepted
content:
application/json:
schema:
$ref: '#/components/schemas/ShipUploadAcceptedResponse'
'400':
$ref: '#/components/responses/InvalidRequestError'
'401':
$ref: '#/components/responses/AuthError'
'403':
$ref: '#/components/responses/ScopeDeniedError'
'409':
$ref: '#/components/responses/DuplicateUploadError'
'429':
$ref: '#/components/responses/RateLimitedError'
'413':
$ref: '#/components/responses/FileTooLargeError'
'415':
$ref: '#/components/responses/InvalidFileFormatError'
'500':
$ref: '#/components/responses/InternalError'
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
integrationKeyHeader:
type: apiKey
in: header
name: x-api-key
parameters:
IdempotencyKeyHeader:
name: Idempotency-Key
in: header
required: false
description: |
Optional idempotency key for retry-safe enqueue semantics.
Scoped by tenant + endpoint + key.
schema:
type: string
minLength: 1
maxLength: 200
responses:
MissingApiKeyError:
description: Missing integration key header
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
example:
code: MISSING_API_KEY
message: Integration key required in x-api-key header
InvalidRequestError:
description: Request validation failed
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
example:
code: INVALID_REQUEST
message: Invalid request payload
AuthError:
description: Authentication failed (invalid/revoked/expired token or key)
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
examples:
invalidToken:
value:
code: INVALID_TOKEN
message: Invalid or expired token
revokedKey:
value:
code: REVOKED_API_KEY
message: This integration key has been revoked
ScopeDeniedError:
description: Principal authenticated but missing required scope(s)
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
example:
code: SCOPE_DENIED
message: Insufficient permissions
details:
required: ['ship:upload']
provided: ['jobs:read']
ActionNotAllowedError:
description: Request conflicts with current resource/action state
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
example:
code: ACTION_NOT_ALLOWED
message: Idempotency-Key was already used with a different request payload
RateLimitedError:
description: Rate limit exceeded
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
example:
code: RATE_LIMITED
message: Rate limit exceeded
details:
bucket: read
limit: 240
windowMs: 60000
retryAfterSeconds: 12
InternalError:
description: Unexpected server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
example:
code: INTERNAL_ERROR
message: An unexpected error occurred
NotFoundError:
description: Requested resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
example:
code: NOT_FOUND
message: Resource not found
DuplicateUploadError:
description: Duplicate file upload rejected
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
example:
code: DUPLICATE_UPLOAD
message: This file has already been uploaded
details:
existingJobId: 11111111-1111-1111-1111-111111111111
uploadedAt: '2026-02-24T13:05:00.000Z'
FileTooLargeError:
description: File exceeds size limit
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
example:
code: FILE_TOO_LARGE
message: File too large. Maximum size is 50MB.
InvalidFileFormatError:
description: File type is not accepted
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
example:
code: INVALID_FILE_FORMAT
message: Only CSV files are allowed
AdapterNotAllowedError:
description: Integration key adapter allowlist denied upload
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
example:
code: ADAPTER_NOT_ALLOWED
message: Requested adapter is not allowed for this integration key
schemas:
ErrorEnvelope:
type: object
required: [code, message]
properties:
code:
type: string
message:
type: string
details:
type: object
additionalProperties: true
IntegrationTokenResponse:
type: object
required: [access_token, token_type, expires_in]
properties:
access_token:
type: string
token_type:
type: string
enum: [Bearer]
expires_in:
type: integer
example: 3600
default_adapter:
type: string
nullable: true
JobAcceptedResponse:
type: object
required: [jobId, status, message]
properties:
jobId:
type: string
format: uuid
status:
type: string
enum: [PENDING, PROCESSING, COMPLETED, FAILED]
message:
type: string
replayed:
type: boolean
description: True when the request replayed an existing job for the same idempotency key.
TradeUploadRequest:
type: object
required: [file]
properties:
file:
type: string
format: binary
runPolicy:
type: string
enum: [always, skip_exact_duplicates]
default: always
screeningAuthority:
type: string
enum: [CA, US]
CatalogUploadRequest:
type: object
required: [file]
properties:
file:
type: string
format: binary
sourceAdapter:
type: string
enum: [catalog-excel, wayfair-excel]
default: catalog-excel
screeningAuthority:
type: string
enum: [CA, US]
UploadAcceptedResponse:
type: object
required: [jobId, status, message, fileName]
properties:
jobId:
type: string
format: uuid
status:
type: string
enum: [PENDING, PROCESSING, COMPLETED, FAILED]
message:
type: string
replayed:
type: boolean
description: True when the request replayed an existing job for the same idempotency key.
fileName:
type: string
CatalogUploadAcceptedResponse:
allOf:
- $ref: '#/components/schemas/UploadAcceptedResponse'
- type: object
required: [sourceAdapter]
properties:
sourceAdapter:
type: string
enum: [catalog-excel, wayfair-excel]
ShipUploadAcceptedResponse:
type: object
required: [jobId, fileName, status]
properties:
jobId:
type: string
format: uuid
fileName:
type: string
status:
type: string
enum: [PENDING]
OrderUploadAcceptedResponse:
allOf:
- $ref: '#/components/schemas/ShipUploadAcceptedResponse'
- type: object
required: [ingestMode]
properties:
ingestMode:
type: string
enum: [PATCH, SNAPSHOT]
JobReconciliation:
type: object
required: [rowsUploaded, rowsSkipped, rowsDeduplicated, skusFound, skusScreened, skusNotApplicable]
properties:
rowsUploaded:
type: integer
nullable: true
rowsSkipped:
type: integer
nullable: true
rowsDeduplicated:
type: integer
nullable: true
skusFound:
type: integer
skusScreened:
type: integer
skusNotApplicable:
type: integer
JobOutcomeCounts:
type: object
required: [atRisk, cleared, needsReview, falsePositive]
properties:
atRisk:
type: integer
cleared:
type: integer
needsReview:
type: integer
falsePositive:
type: integer
JobSkippedRows:
type: object
required: [counts]
properties:
counts:
type: object
nullable: true
additionalProperties:
type: integer
sample:
type: array
nullable: true
items:
type: object
additionalProperties: true
JobResponse:
type: object
required:
- id
- type
- status
- progress
- result
- reconciliation
- skippedRows
- warnings
- outcomes
- error
- createdAt
- updatedAt
properties:
id:
type: string
format: uuid
type:
type: string
status:
type: string
enum: [PENDING, PROCESSING, COMPLETED, FAILED]
progress:
type: integer
fileName:
type: string
result:
type: object
additionalProperties: true
reconciliation:
$ref: '#/components/schemas/JobReconciliation'
skippedRows:
$ref: '#/components/schemas/JobSkippedRows'
warnings:
type: object
nullable: true
additionalProperties:
type: integer
outcomes:
$ref: '#/components/schemas/JobOutcomeCounts'
error:
type: string
nullable: true
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
JobsListResponse:
type: object
required: [jobs, count]
properties:
jobs:
type: array
items:
$ref: '#/components/schemas/JobResponse'
count:
type: integer
SimaBatchRequest:
type: object
properties:
skus:
type: array
nullable: true
items:
type: string
runPolicy:
type: string
enum: [always, skip_exact_duplicates]
default: always
screeningAuthority:
type: string
enum: [CA, US]
SimaResultItem:
type: object
required:
- id
- sku
- outcome
- status
- workflowStatus
- hsInScope
- currentHs
- confidence
- analysisDate
- isStale
- exposureAnnual
- missingAttributes
properties:
id:
type: string
format: cuid
sku:
type: string
outcome:
type: string
enum: [AT_RISK, NEEDS_REVIEW, CLEARED]
status:
type: string
enum: [AT_RISK, NEEDS_REVIEW, CLEARED]
workflowStatus:
type: string
nullable: true
enum: [OPEN, OVERRIDDEN, ACCEPTED, DISMISSED]
reasonCode:
type: string
nullable: true
measureCode:
type: string
nullable: true
hsInScope:
type: boolean
currentHs:
type: string
correctedHs:
type: string
nullable: true
countryOfOrigin:
type: string
nullable: true
materialType:
type: string
nullable: true
confidence:
type: number
evidence:
type: object
nullable: true
additionalProperties: true
analysisDate:
type: string
format: date-time
simaConfigVersion:
type: string
nullable: true
needsReviewSince:
type: string
format: date-time
nullable: true
isStale:
type: boolean
exposureAnnual:
type: number
nullable: true
adRate:
type: number
nullable: true
cvdRate:
type: number
nullable: true
combinedRate:
type: number
nullable: true
caseNumber:
type: string
nullable: true
hasRestrictedComponents:
type: boolean
missingAttributes:
type: array
items:
type: string
SimaResultsResponse:
type: object
required: [outcomes, total, limit, hasMore, cursor]
properties:
outcomes:
type: array
items:
$ref: '#/components/schemas/SimaResultItem'
total:
type: integer
limit:
type: integer
offset:
type: integer
cursor:
type: string
nullable: true
hasMore:
type: boolean
SimaSummaryResponse:
type: object
required: [totalSkus, atRisk, needsReview, totalExposure]
properties:
totalSkus:
type: integer
atRisk:
type: integer
needsReview:
type: integer
totalExposure:
type: number
SimaEvidenceResponse:
type: object
required: [result, classification, attributes, measureApplicability, thresholds, exposure, history, auditTrail]
properties:
result:
type: object
additionalProperties: true
classification:
type: object
additionalProperties: true
attributes:
type: object
additionalProperties: true
measureApplicability:
type: object
additionalProperties: true
thresholds:
type: object
additionalProperties: true
exposure:
type: object
additionalProperties: true
history:
type: array
items:
type: object
additionalProperties: true
auditTrail:
type: array
items:
type: object
additionalProperties: true
SimaReportJsonResponse:
type: object
required: [generatedAt, tenantId, configVersion]
properties:
generatedAt:
type: string
format: date-time
tenantId:
type: string
format: uuid
configVersion:
type: string
totalOutcomes:
type: integer
totalExposures:
type: integer
outcomes:
type: array
items:
type: object
additionalProperties: true
exposures:
type: array
items:
type: object
additionalProperties: true