Dashboard Push API
Endpoint
Section titled “Endpoint”POST /v1/dashboard/pushAuthentication: API key via X-API-Key header.
Required tier: Team+ (hosted_dashboard feature).
CLI Usage
Section titled “CLI Usage”The CLI wraps this endpoint. After a scan, push results in one command:
complyform dashboard push --project-label=prod-gcpThe CLI reads scan results from the local state, serializes them, and posts to the API. You do not need to construct the JSON payload manually unless you are integrating outside the CLI.
Request
Section titled “Request”Headers
Section titled “Headers”Content-Type: application/jsonX-API-Key: cf_api_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx{ "project_label": "prod-gcp", "cloud": "gcp", "cloud_account_id": "my-org-project-123", "frameworks": ["cis_gcp_v2.0", "soc2"], "score": 78.4, "passed": 142, "failed": 39, "severity_counts": { "critical": 3, "high": 12, "medium": 18, "low": 6 }, "findings": [ { "rule_id": "cis_gcp_v2.0_2.1", "resource": "google_sql_database_instance.production", "status": "FAIL", "severity": "high", "message": "Cloud SQL instance does not enforce SSL connections", "remediation": "Set `settings.ip_configuration.require_ssl = true`" }, { "rule_id": "cis_gcp_v2.0_4.3", "resource": "google_compute_firewall.allow_all_ingress", "status": "FAIL", "severity": "critical", "message": "Firewall rule allows unrestricted ingress on all ports", "remediation": "Restrict source_ranges from 0.0.0.0/0 to specific CIDRs" } ], "state_source": "local", "scanned_at": "2026-03-23T14:30:00Z"}| Field | Type | Required | Description |
|---|---|---|---|
project_label | string | yes | Unique label for the project within your account |
cloud | string | yes | Cloud provider: gcp, aws, or azure |
cloud_account_id | string | yes | Cloud account or project identifier |
frameworks | string[] | yes | List of framework IDs scanned |
score | number | yes | Overall compliance score (0-100) |
passed | integer | yes | Number of passed checks |
failed | integer | yes | Number of failed checks |
severity_counts | object | yes | Breakdown by severity: critical, high, medium, low |
findings | object[] | yes | Array of individual finding objects |
state_source | string | yes | Source of Terraform state: local, remote, or ci |
scanned_at | string | yes | ISO 8601 timestamp of the scan |
Response
Section titled “Response”200 OK
Section titled “200 OK”{ "project_id": "proj_a1b2c3d4e5f6", "scan_id": "scan_20260323_143000_prod-gcp", "score_delta": -2.1, "dashboard_url": "https://dashboard.complyform.dev/projects/proj_a1b2c3d4e5f6/scans/scan_20260323_143000_prod-gcp"}| Field | Type | Description |
|---|---|---|
project_id | string | Stable project identifier |
scan_id | string | Unique scan identifier for this push |
score_delta | number | Change from the previous scan score (negative = regression) |
dashboard_url | string | Direct link to view this scan in the dashboard |
Key Behaviors
Section titled “Key Behaviors”Score Delta Calculation
Section titled “Score Delta Calculation”score_delta is computed as an atomic Firestore transaction. The API reads the previous scan’s score and writes the new score in a single operation, preventing race conditions when multiple CI jobs push concurrently.
Findings Storage
Section titled “Findings Storage”Individual findings are stored in Google Cloud Storage, not in Firestore. The Firestore document for each scan contains metadata (score, counts, timestamp) and a GCS reference to the full findings payload. This keeps Firestore document sizes small and query performance predictable.
Project Matching and Creation
Section titled “Project Matching and Creation”The API matches on project_label within your account:
- If a project with that label exists, the scan is appended to its history.
- If no matching project exists, one is created automatically.
Project Limits
Section titled “Project Limits”The number of active projects is capped by tier:
| Tier | Max Projects |
|---|---|
| Team | 1 |
| Agency | 5 |
Pushing to a new project_label when you have reached your limit returns 409.
Error Responses
Section titled “Error Responses”403 Forbidden
Section titled “403 Forbidden”{ "error": "insufficient_tier", "message": "hosted_dashboard requires Team tier or above. Current tier: Individual."}Your license does not include the hosted_dashboard feature. Upgrade to Team+ to use the dashboard push API.
409 Conflict
Section titled “409 Conflict”{ "error": "project_limit_reached", "message": "Team tier allows 1 project. Archive an existing project or upgrade to Agency."}You have reached the maximum number of active projects for your tier.
429 Too Many Requests
Section titled “429 Too Many Requests”{ "error": "rate_limit_exceeded", "message": "Dashboard write limit: 5/min. Retry after 42 seconds."}Back off and retry. In CI/CD pipelines, add a delay between parallel scan jobs that push results.
CI/CD Integration
Section titled “CI/CD Integration”For automated pushes in CI/CD pipelines, see the CI/CD guide which covers GitHub Actions, GitLab CI, and other providers.
Ensure your API key is stored as a secret in your CI environment — never hardcode it in pipeline definitions. See Authentication for key storage guidance.