Skip to content

Build project report

POST
/api/v1/org/{org}/ws/{workspace}/airt/projects/{project}/reports/build
curl --request POST \
--url https://example.com/api/v1/org/example/ws/example/airt/projects/example/reports/build \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "preset": { "branding": { "company_name": "example", "confidentiality_footer": "example", "logo_oid": "example", "report_title": "example" }, "compliance_frameworks": [ "owasp_llm_top_10" ], "filters": { "assessment_ids": [ "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0" ], "attack_name": [ "example" ], "category": [ "example" ], "finding_type": [ "jailbreak" ], "include_undated_assessments": false, "min_score": 1, "severity": [ "critical" ], "started_after": "2026-04-15T12:00:00Z", "started_before": "2026-04-15T12:00:00Z" }, "format": "pdf", "include_adversarial": false, "sections": [ "risk_score_metrics" ], "style": { "font": "Helvetica", "font_size": 11 } }, "template_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0" }'

Start an async report-build job. Returns 202 with a job id to poll until the rendered artifact’s signed URL is available. Returns 422 synchronously when any selected section resolves to zero rows — preflight the request via the preflight endpoint to avoid the round-trip.

org
required
Org

Organization slug

string

Organization slug

workspace
required
Workspace

Workspace slug

string

Workspace slug

project
required
Project

Project slug or UUID

string

Project slug or UUID

Media typeapplication/json
ReportBuildRequest

Payload for the (future) POST /airt/projects/{project}/reports/build.

Exactly one of preset (inline) or template_id (stored template).

object
preset
Any of:
AirtPresetRequest

Simple AIRT-report request — what the frontend POSTs for template create or inline build. Server expands to ReportTemplateSchema via build_airt_components.

object
branding
Any of:
BrandingOverrides

Optional branding slots. Expanded into Header/Footer/Title by the preset builder. Frontend-facing only — no direct DreadReport equivalent, but the expansion produces DreadReport-valid components.

object
company_name
Any of:
string
>= 1 characters <= 255 characters
confidentiality_footer
Any of:
string
<= 500 characters
logo_oid
Any of:
string
/^[A-Za-z0-9._\-/]{1,256}$/
report_title
Any of:
string
>= 1 characters <= 255 characters
compliance_frameworks
Compliance Frameworks
Array<string>
<= 5 items
Allowed values: owasp_llm_top_10 owasp_agentic_top_10 mitre_atlas nist_ai_rmf google_saif
filters
Any of:
FindingsFilter

Filter over findings rows. All strings untrusted.

Scope: these fields narrow the findings table rows only. Report-wide assessment scoping (narrow ASR / severity / metrics sections by the same assessment subset) is a follow-up — see ENG-6432 PR description. For Phase 1 the UI-surfaced assessment/date filters apply only to the findings table component.

object
assessment_ids
Any of:
Array<string>
<= 100 items
attack_name
Any of:
Array<string>
<= 100 items
category
Any of:
Array<string>
<= 100 items
finding_type
Any of:
Array<string>
<= 7 items
Allowed values: jailbreak partial refusal error evasion degradation robust
include_undated_assessments
Include Undated Assessments
boolean
min_score
Any of:
number
<= 1
severity
Any of:
Array<string>
<= 5 items
Allowed values: critical high medium low info
started_after
Any of:
string format: date-time
started_before
Any of:
string format: date-time
format
Format
string
default: pdf
Allowed values: pdf docx csv
include_adversarial
Include Adversarial
boolean
sections
required
Sections
Array<string>
>= 1 items <= 8 items
Allowed values: risk_score_metrics severity_breakdown findings_table asr_by_attack asr_by_category transform_effectiveness compliance_coverage models_used
style
StyleConfig

Document-wide style. Mirrors DreadReport.style() — font, font_size.

Fonts locked to the ReportLab built-in set (no file I/O at render time).

object
font
Font
string
default: Helvetica
Allowed values: Helvetica Times-Roman Courier
font_size
Font Size
integer
default: 11 >= 8 <= 24
template_id
Any of:
string format: uuid

Successful Response

Media typeapplication/json
BuildJobResponse

Shape returned by POST .../reports/build and GET .../reports/build/{id}.

presigned_url / url_expires_at / file_size_bytes populate only after status == COMPLETED. error_message populates only on FAILED. The empty_sections error is a separate 422 response — those never transit through this model.

object
completed_at
Any of:
string format: date-time
created_at
required
Created At
string format: date-time
error_message
Any of:
string
file_size_bytes
File Size Bytes
integer
0
job_id
required
Job Id
string format: uuid
presigned_url
Any of:
string
status
required
AirtBuildJobStatus

Lifecycle states for an async report-build job.

string
Allowed values: queued in_progress completed failed
url_expires_at
Any of:
string format: date-time
Example
{
"file_size_bytes": 0,
"status": "queued"
}

Invalid request

Media typeapplication/json
APIErrorPayload

Canonical API error envelope returned by the API.

object
code
required
Code

HTTP status code

integer
Allowed values: 400 401 403 404 409 422 426 429 500 502 504
detail
required
Detail

Human-readable error message

string
errors
Any of:
Array<object>
ValidationErrorItem
object
loc
required
Loc

Where the validation error occurred

Array
msg
required
Msg

Human-readable validation message

string
type
required
Type

Machine-readable validation error type

string
type
required
Type

Stable machine-readable error type

string
Allowed values: already_exists_error app_error authentication_error conflict_error aws_error configuration_error database_error dynamodb_error e2b_error e2b_rate_limit_error expired_signature_error expired_token_error forbidden_error group_error invalid_error invalid_flag_error invalid_username_error mail_error member_exists_error member_limit_exceeded_error migration_lock_timeout_error not_found_error oauth_config_error org_sandbox_capacity_exceeded_error bad_gateway_error gateway_timeout_error s3_error server_error task_error stripe_error task_set_not_found token_error upgrade_required_error usage_limit_exceeded_error user_suspended user_verification_error validation_error
Example
{
"code": 401,
"detail": "Authentication failed",
"type": "authentication_error"
}

Authentication failed

Media typeapplication/json
APIErrorPayload

Canonical API error envelope returned by the API.

object
code
required
Code

HTTP status code

integer
Allowed values: 400 401 403 404 409 422 426 429 500 502 504
detail
required
Detail

Human-readable error message

string
errors
Any of:
Array<object>
ValidationErrorItem
object
loc
required
Loc

Where the validation error occurred

Array
msg
required
Msg

Human-readable validation message

string
type
required
Type

Machine-readable validation error type

string
type
required
Type

Stable machine-readable error type

string
Allowed values: already_exists_error app_error authentication_error conflict_error aws_error configuration_error database_error dynamodb_error e2b_error e2b_rate_limit_error expired_signature_error expired_token_error forbidden_error group_error invalid_error invalid_flag_error invalid_username_error mail_error member_exists_error member_limit_exceeded_error migration_lock_timeout_error not_found_error oauth_config_error org_sandbox_capacity_exceeded_error bad_gateway_error gateway_timeout_error s3_error server_error task_error stripe_error task_set_not_found token_error upgrade_required_error usage_limit_exceeded_error user_suspended user_verification_error validation_error
Example
{
"code": 401,
"detail": "Authentication failed",
"type": "authentication_error"
}

Access forbidden

Media typeapplication/json
APIErrorPayload

Canonical API error envelope returned by the API.

object
code
required
Code

HTTP status code

integer
Allowed values: 400 401 403 404 409 422 426 429 500 502 504
detail
required
Detail

Human-readable error message

string
errors
Any of:
Array<object>
ValidationErrorItem
object
loc
required
Loc

Where the validation error occurred

Array
msg
required
Msg

Human-readable validation message

string
type
required
Type

Machine-readable validation error type

string
type
required
Type

Stable machine-readable error type

string
Allowed values: already_exists_error app_error authentication_error conflict_error aws_error configuration_error database_error dynamodb_error e2b_error e2b_rate_limit_error expired_signature_error expired_token_error forbidden_error group_error invalid_error invalid_flag_error invalid_username_error mail_error member_exists_error member_limit_exceeded_error migration_lock_timeout_error not_found_error oauth_config_error org_sandbox_capacity_exceeded_error bad_gateway_error gateway_timeout_error s3_error server_error task_error stripe_error task_set_not_found token_error upgrade_required_error usage_limit_exceeded_error user_suspended user_verification_error validation_error
Example
{
"code": 401,
"detail": "Authentication failed",
"type": "authentication_error"
}

Not found

Media typeapplication/json
APIErrorPayload

Canonical API error envelope returned by the API.

object
code
required
Code

HTTP status code

integer
Allowed values: 400 401 403 404 409 422 426 429 500 502 504
detail
required
Detail

Human-readable error message

string
errors
Any of:
Array<object>
ValidationErrorItem
object
loc
required
Loc

Where the validation error occurred

Array
msg
required
Msg

Human-readable validation message

string
type
required
Type

Machine-readable validation error type

string
type
required
Type

Stable machine-readable error type

string
Allowed values: already_exists_error app_error authentication_error conflict_error aws_error configuration_error database_error dynamodb_error e2b_error e2b_rate_limit_error expired_signature_error expired_token_error forbidden_error group_error invalid_error invalid_flag_error invalid_username_error mail_error member_exists_error member_limit_exceeded_error migration_lock_timeout_error not_found_error oauth_config_error org_sandbox_capacity_exceeded_error bad_gateway_error gateway_timeout_error s3_error server_error task_error stripe_error task_set_not_found token_error upgrade_required_error usage_limit_exceeded_error user_suspended user_verification_error validation_error
Example
{
"code": 401,
"detail": "Authentication failed",
"type": "authentication_error"
}

Already exists

Media typeapplication/json
APIErrorPayload

Canonical API error envelope returned by the API.

object
code
required
Code

HTTP status code

integer
Allowed values: 400 401 403 404 409 422 426 429 500 502 504
detail
required
Detail

Human-readable error message

string
errors
Any of:
Array<object>
ValidationErrorItem
object
loc
required
Loc

Where the validation error occurred

Array
msg
required
Msg

Human-readable validation message

string
type
required
Type

Machine-readable validation error type

string
type
required
Type

Stable machine-readable error type

string
Allowed values: already_exists_error app_error authentication_error conflict_error aws_error configuration_error database_error dynamodb_error e2b_error e2b_rate_limit_error expired_signature_error expired_token_error forbidden_error group_error invalid_error invalid_flag_error invalid_username_error mail_error member_exists_error member_limit_exceeded_error migration_lock_timeout_error not_found_error oauth_config_error org_sandbox_capacity_exceeded_error bad_gateway_error gateway_timeout_error s3_error server_error task_error stripe_error task_set_not_found token_error upgrade_required_error usage_limit_exceeded_error user_suspended user_verification_error validation_error
Example
{
"code": 401,
"detail": "Authentication failed",
"type": "authentication_error"
}

One or more selected report sections have no data.

Media typeapplication/json
EmptyReportSectionsResponse

Shared shape for both the Build 422 body and the Preflight 200 body.

One schema, two paths: the UI consumes the same structure whether the empty-check fires synchronously at build time or proactively via preflight before the user clicks Build.

object
detail
Detail
string
default: One or more selected report sections have no data.
empty_sections
Empty Sections
Array<object>
EmptySection

One offending section in an empty-sections response.

key is the AirtSectionPreset checkbox identifier when the section came from a preset request. Template-authored sections have no preset origin; key is None there and the frontend falls back to title.

object
key
Any of:
string
Allowed values: risk_score_metrics severity_breakdown findings_table asr_by_attack asr_by_category transform_effectiveness compliance_coverage models_used
title
required
Title
string
Example
{
"detail": "One or more selected report sections have no data.",
"empty_sections": [
{
"key": "risk_score_metrics"
}
]
}

Upgrade required

Media typeapplication/json
APIErrorPayload

Canonical API error envelope returned by the API.

object
code
required
Code

HTTP status code

integer
Allowed values: 400 401 403 404 409 422 426 429 500 502 504
detail
required
Detail

Human-readable error message

string
errors
Any of:
Array<object>
ValidationErrorItem
object
loc
required
Loc

Where the validation error occurred

Array
msg
required
Msg

Human-readable validation message

string
type
required
Type

Machine-readable validation error type

string
type
required
Type

Stable machine-readable error type

string
Allowed values: already_exists_error app_error authentication_error conflict_error aws_error configuration_error database_error dynamodb_error e2b_error e2b_rate_limit_error expired_signature_error expired_token_error forbidden_error group_error invalid_error invalid_flag_error invalid_username_error mail_error member_exists_error member_limit_exceeded_error migration_lock_timeout_error not_found_error oauth_config_error org_sandbox_capacity_exceeded_error bad_gateway_error gateway_timeout_error s3_error server_error task_error stripe_error task_set_not_found token_error upgrade_required_error usage_limit_exceeded_error user_suspended user_verification_error validation_error
Example
{
"code": 401,
"detail": "Authentication failed",
"type": "authentication_error"
}

Rate limited

Media typeapplication/json
APIErrorPayload

Canonical API error envelope returned by the API.

object
code
required
Code

HTTP status code

integer
Allowed values: 400 401 403 404 409 422 426 429 500 502 504
detail
required
Detail

Human-readable error message

string
errors
Any of:
Array<object>
ValidationErrorItem
object
loc
required
Loc

Where the validation error occurred

Array
msg
required
Msg

Human-readable validation message

string
type
required
Type

Machine-readable validation error type

string
type
required
Type

Stable machine-readable error type

string
Allowed values: already_exists_error app_error authentication_error conflict_error aws_error configuration_error database_error dynamodb_error e2b_error e2b_rate_limit_error expired_signature_error expired_token_error forbidden_error group_error invalid_error invalid_flag_error invalid_username_error mail_error member_exists_error member_limit_exceeded_error migration_lock_timeout_error not_found_error oauth_config_error org_sandbox_capacity_exceeded_error bad_gateway_error gateway_timeout_error s3_error server_error task_error stripe_error task_set_not_found token_error upgrade_required_error usage_limit_exceeded_error user_suspended user_verification_error validation_error
Example
{
"code": 401,
"detail": "Authentication failed",
"type": "authentication_error"
}

Internal server error

Media typeapplication/json
APIErrorPayload

Canonical API error envelope returned by the API.

object
code
required
Code

HTTP status code

integer
Allowed values: 400 401 403 404 409 422 426 429 500 502 504
detail
required
Detail

Human-readable error message

string
errors
Any of:
Array<object>
ValidationErrorItem
object
loc
required
Loc

Where the validation error occurred

Array
msg
required
Msg

Human-readable validation message

string
type
required
Type

Machine-readable validation error type

string
type
required
Type

Stable machine-readable error type

string
Allowed values: already_exists_error app_error authentication_error conflict_error aws_error configuration_error database_error dynamodb_error e2b_error e2b_rate_limit_error expired_signature_error expired_token_error forbidden_error group_error invalid_error invalid_flag_error invalid_username_error mail_error member_exists_error member_limit_exceeded_error migration_lock_timeout_error not_found_error oauth_config_error org_sandbox_capacity_exceeded_error bad_gateway_error gateway_timeout_error s3_error server_error task_error stripe_error task_set_not_found token_error upgrade_required_error usage_limit_exceeded_error user_suspended user_verification_error validation_error
Example
{
"code": 401,
"detail": "Authentication failed",
"type": "authentication_error"
}

Bad gateway

Media typeapplication/json
APIErrorPayload

Canonical API error envelope returned by the API.

object
code
required
Code

HTTP status code

integer
Allowed values: 400 401 403 404 409 422 426 429 500 502 504
detail
required
Detail

Human-readable error message

string
errors
Any of:
Array<object>
ValidationErrorItem
object
loc
required
Loc

Where the validation error occurred

Array
msg
required
Msg

Human-readable validation message

string
type
required
Type

Machine-readable validation error type

string
type
required
Type

Stable machine-readable error type

string
Allowed values: already_exists_error app_error authentication_error conflict_error aws_error configuration_error database_error dynamodb_error e2b_error e2b_rate_limit_error expired_signature_error expired_token_error forbidden_error group_error invalid_error invalid_flag_error invalid_username_error mail_error member_exists_error member_limit_exceeded_error migration_lock_timeout_error not_found_error oauth_config_error org_sandbox_capacity_exceeded_error bad_gateway_error gateway_timeout_error s3_error server_error task_error stripe_error task_set_not_found token_error upgrade_required_error usage_limit_exceeded_error user_suspended user_verification_error validation_error
Example
{
"code": 401,
"detail": "Authentication failed",
"type": "authentication_error"
}

Gateway timeout

Media typeapplication/json
APIErrorPayload

Canonical API error envelope returned by the API.

object
code
required
Code

HTTP status code

integer
Allowed values: 400 401 403 404 409 422 426 429 500 502 504
detail
required
Detail

Human-readable error message

string
errors
Any of:
Array<object>
ValidationErrorItem
object
loc
required
Loc

Where the validation error occurred

Array
msg
required
Msg

Human-readable validation message

string
type
required
Type

Machine-readable validation error type

string
type
required
Type

Stable machine-readable error type

string
Allowed values: already_exists_error app_error authentication_error conflict_error aws_error configuration_error database_error dynamodb_error e2b_error e2b_rate_limit_error expired_signature_error expired_token_error forbidden_error group_error invalid_error invalid_flag_error invalid_username_error mail_error member_exists_error member_limit_exceeded_error migration_lock_timeout_error not_found_error oauth_config_error org_sandbox_capacity_exceeded_error bad_gateway_error gateway_timeout_error s3_error server_error task_error stripe_error task_set_not_found token_error upgrade_required_error usage_limit_exceeded_error user_suspended user_verification_error validation_error
Example
{
"code": 401,
"detail": "Authentication failed",
"type": "authentication_error"
}