Overview

The Upload Evidence API allows external systems, CI/CD pipelines, and scripts to programmatically upload evidence files and attach them to compliance tests in LowerPlane. This is useful for automating evidence collection from tools that don’t have a native integration.

Authentication

All requests require an API key passed as a Bearer token in the Authorization header.
Authorization: Bearer lp_your_api_key_here
API keys can be generated from Settings > API Keys in the LowerPlane dashboard. Keys must start with lp_.

Endpoints

Upload Evidence to a Test

Upload an evidence file and attach it to a specific test.
POST /api/v1/external/tests/{test_id}/evidence

Upload Evidence to a Test Entity

Upload an evidence file and attach it to a specific entity (resource) within a test. Use the entity’s resource_id (the provider’s identifier, e.g., AWS ARN, Okta user ID) to identify the entity.
POST /api/v1/external/tests/{test_id}/entities/{resource_id}/evidence
You can find the resource_id for any entity by clicking on it in the test detail view. The Resource ID is displayed at the top of the entity detail modal with a copy button.

Request

Authorization
string
required
Bearer token with your API key. Example: Bearer lp_abc123...
test_id
string
required
The UUID of the test to attach evidence to.
resource_id
string
The resource ID of the specific test entity. This is the provider’s identifier (e.g., AWS ARN, GitHub repo name, Okta user ID), not LowerPlane’s internal UUID.
file
file
required
The evidence file to upload. Supports PDF, PNG, JPG, CSV, JSON, DOCX, and other common file types. Maximum size: 50MB.
name
string
Display name for the evidence. Defaults to the uploaded filename if not provided.
description
string
Description of the evidence.
type
string
default:"document"
Evidence type. One of: document, screenshot, report, log, certificate, configuration.
valid_from
string
ISO 8601 date when the evidence becomes valid. Defaults to the current timestamp.
valid_until
string
ISO 8601 date when the evidence expires.

Response

id
string
The UUID of the created evidence record.
name
string
Display name of the evidence.
file_name
string
Original filename.
file_size
number
File size in bytes.
type
string
Evidence type.
test_id
string
The test this evidence is attached to.
entity_resource_id
string
The resource ID of the entity this evidence is attached to, or null for test-level evidence.
created_at
string
ISO 8601 timestamp of when the evidence was created.

Examples

Upload test-level evidence

curl -X POST \
  https://app.lowerplane.com/api/v1/external/tests/abc123-test-id/evidence \
  -H "Authorization: Bearer lp_your_api_key" \
  -F "file=@./security-scan-report.pdf" \
  -F "name=Monthly Security Scan Report" \
  -F "description=Automated vulnerability scan results for June 2026" \
  -F "type=report"

Upload entity-level evidence

curl -X POST \
  https://app.lowerplane.com/api/v1/external/tests/abc123-test-id/entities/arn:aws:s3:::my-bucket/evidence \
  -H "Authorization: Bearer lp_your_api_key" \
  -F "file=@./bucket-encryption-config.json" \
  -F "name=S3 Bucket Encryption Configuration" \
  -F "type=configuration"

Upload from a CI/CD pipeline

# GitHub Actions example
- name: Upload compliance evidence
  run: |
    curl -X POST \
      "${{ secrets.LOWERPLANE_URL }}/api/v1/external/tests/${{ vars.TEST_ID }}/evidence" \
      -H "Authorization: Bearer ${{ secrets.LOWERPLANE_API_KEY }}" \
      -F "file=@./test-results.json" \
      -F "name=CI/CD Test Results - Build #${{ github.run_number }}" \
      -F "type=report" \
      -F "description=Automated test results from GitHub Actions"

Python example

import requests

api_key = "lp_your_api_key"
test_id = "abc123-test-id"
url = f"https://app.lowerplane.com/api/v1/external/tests/{test_id}/evidence"

with open("audit-log.csv", "rb") as f:
    response = requests.post(
        url,
        headers={"Authorization": f"Bearer {api_key}"},
        files={"file": ("audit-log.csv", f, "text/csv")},
        data={
            "name": "Monthly Audit Log Export",
            "type": "log",
            "description": "Exported audit logs for compliance review",
        },
    )

print(response.json())

Error Responses

StatusErrorDescription
400file is requiredNo file was included in the request
401Missing or invalid Authorization headerNo Bearer token provided
401Invalid API key formatKey doesn’t start with lp_
401Invalid or revoked API keyKey not found or has been revoked
404Test not foundTest ID doesn’t exist or doesn’t belong to your organization
404Entity with resource_id "..." not found in this testThe specified resource ID wasn’t found in the test’s entities

Finding IDs

Test ID

Navigate to the test in LowerPlane. The test ID is in the URL: /app/tests/{test_id}.

Resource ID

Open the test detail view, go to the Entities tab, and click on any entity. The Resource ID is displayed at the top of the detail modal with a copy button. This is the provider’s identifier (e.g., AWS ARN, GitHub repository name, Okta user login).