This article provides an example of how to use the Paramify API to continuously upload evidence into Paramify.
Contents
Part 1: Set-up
- 1.1 Download Repository
- 1.2 Create & set up a Paramify Evidence API Key
Part 2: Architecture and Design
- 2.1 Resource Overview
- 2.2 Evidence Sets vs. Artifacts
- 2.3 Script Process
- 2.4 Key API Endpoints Used
Part 3: Upload an Evidence File
Appendix: Technical summary of API calls with code snippets
Part 1: Set-up
1.1 Download Repository
-
Download the zip file
https://support.paramify.com/hc/en-us/article_attachments/43295255437971
-
Expand the zip file and open the folder
paramify_api_integration
-
Install dependencies if needed (macOS example):
brew install jq curl -
Create an environment variable
.envfile based on the template (paramify_env_template.txt) using the following command
cp paramify_api_integration/paramify_env_template.txt .env
1.2 Create & set up a Paramify Evidence API Key
-
Create a Paramify API Key with View & Write Evidence Permissions.
See this guide for the process of creating an API Key in Paramify: -
Add the API Key to your environment variables
.envfile.
Required.envconfiguration:
PARAMIFY_UPLOAD_API_TOKEN=<your_actual_token_here> PARAMIFY_API_BASE_URL=https://app.paramify.com/api/v0 # (optional, defaults to this value)
Part 2: Architecture and Design
2.1 Resource Overview
-
paramify_evidence_uploader.sh– Main uploader script that handles Evidence Sets and Artifacts -
paramify_env_template.txt– Environment variables template for API token -
paramify_evidence_mappings.json– Mapping of scripts to Evidence Sets and metadata - Official Paramify API Docs – Official Paramify API documentation
2.2 Evidence Sets vs. Artifacts
- Evidence Sets: Created once per type of evidence / script that produces evidence. Evidence Sets serve as containers for related compliance evidence.
- Artifacts: Individual evidence files from validation runs. Multiple artifacts can be attached to each Evidence Set over time.
2.3 Script Process
-
The
paramify_evidence_uploader.shscript takes two inputs as command line arguments:
(1) evidence script/process name (2) evidence artifact file path./paramify_api_integration/paramify_evidence_uploader.sh --script <script_name> --file <output_file>
For example:
./paramify_api_integration/paramify_evidence_uploader.sh --script load_balancer_encryption_status.sh --file evidence/load_balancer_encryption_status.json
-
Checks if an Evidence Set exists for the script/process. If not, creates it with details from
paramify_evidence_mappings.jsonFor example:"load_balancer_encryption_status.sh": { "referenceId": "EVD-LB-ENC", "name": "Load Balancer Encryption", "description": "Evidence for load balancer SSL/TLS encryption configurations", "instructions": "Script: load_balancer_encryption_status.sh. Commands executed: 1) Describe load balancers: `aws elbv2 describe-load-balancers` 2) Check listeners: `aws elbv2 describe-listeners --load-balancer-arn <arn> --query \"Listeners[*].{Port:Port,Protocol:Protocol,SslPolicy:SslPolicy}\"`", "automated": true } - Uploads the evidence file as an artifact with metadata (title, note, effective date).
For example:Automated validation results from load_balancer_encryption_status.sh script executed on 2025-07-24 at 21:19:34 UTC
4. Audit trail of all uploads is maintained in Paramify Activity Log.
2.4 Key API Endpoints Used
- GET /evidence - Retrieve all Evidence Sets to check for existing ones
- POST /evidence - Create new Evidence Set with metadata
- POST /evidence/{evidence_id}/artifacts/upload - Upload file artifacts with metadata
A technical summary of the key API calls with code snippets is included at the end of this writeup. See this guide for help accessing the Paramify API documentation:
"Access Paramify API Documentation" Guide
Part 3: Upload an Evidence File
Find the file path to your evidence script/process and evidence artifact. Pass these in as command line arguments to the paramify_evidence_uploader.sh script.
# Upload an evidence file to Paramify
./paramify_api_integration/paramify_evidence_uploader.sh --script <script_name> --file <output_file>
# Example:
./paramify_api_integration/paramify_evidence_uploader.sh --script s3_encryption_status.sh --file evidence/s3_encryption_status.jsonA successful result will look similar to the following:
Appendix: Technical summary of API calls with code snippets
1. Core API Infrastructure
# Base API configuration
PARAMIFY_API_BASE_URL="https://app.paramify.com/api/v0"
PARAMIFY_UPLOAD_API_TOKEN="your_api_token"
# Generic API call function
make_api_call() {
local method="$1"
local endpoint="$2"
local data="$3"
curl -s -X "$method" \
-H "Authorization: Bearer $PARAMIFY_UPLOAD_API_TOKEN" \
-H "Content-Type: application/json" \
-d "$data" \
"$PARAMIFY_API_BASE_URL$endpoint"
}2. Check for Existing Evidence Set
# API Call: GET /evidence
find_existing_evidence_object() {
local reference_id="$1"
local response_code=$(make_api_call "GET" "/evidence")
if [ "$response_code" = "200" ]; then
local evidence_id=$(cat response.json | jq -r --arg ref_id "$reference_id"
'.evidences[] | select(.referenceId == $ref_id) | .id')
echo "$evidence_id"
fi
}3. Create New Evidence Set
# API Call: POST /evidence
create_evidence_object() {
local evidence_data=$(jq -n \
--arg ref_id "$reference_id" \
--arg name "$name" \
--arg desc "$description" \
--arg instr "$instructions" \
--argjson auto "$automated" \
'{
referenceId: $ref_id,
name: $name,
description: $desc,
instructions: $instr,
automated: $auto
}')
local response_code=$(make_api_call "POST" "/evidence" "$evidence_data")
if [ "$response_code" = "201" ] || [ "$response_code" = "200" ]; then
local evidence_id=$(cat response.json | jq -r '.id')
echo "$evidence_id"
fi
}4. Upload Evidence Artifact
# API Call: POST /evidence/{evidence_id}/artifacts/upload
upload_file_artifact() {
local evidence_id="$1"
local file_path="$2"
local title="$3"
local note="$4"
# Create artifact metadata
local artifact_json=$(jq -n \
--arg title "$title" \
--arg note "$note" \
--arg effectiveDate "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
'{title: $title, note: $note, effectiveDate: $effectiveDate}')
# Upload using multipart form data
curl -s \
-H "Authorization: Bearer $PARAMIFY_UPLOAD_API_TOKEN" \
-X POST \
"$PARAMIFY_API_BASE_URL/evidence/$evidence_id/artifacts/upload" \
-F "file=@$file_path" \
-F "artifact=@artifact.json;type=application/json"
}5. Script Mapping Lookup
# Get script configuration from mappings file
get_script_mapping() {
local script_name="$1"
local mapping=$(jq -r --arg script "$script_name"
'.scriptMappings[$script]' "paramify_evidence_mappings.json")
# Returns mapping object with:
# - referenceId: "EVD-LB-ENC"
# - name: "Load Balancer Encryption"
# - description: "Evidence for load balancer SSL/TLS encryption configurations"
# - instructions: "Script commands and process..."
# - automated: true
}6. Main Process Flow
# Complete workflow
upload_script_evidence() {
local script_name="$1"
local script_output_file="$2"
# 1. Get script mapping
local mapping=$(get_script_mapping "$script_name")
local reference_id=$(echo "$mapping" | jq -r '.referenceId')
# 2. Find or create Evidence Object
local evidence_id
if evidence_id=$(find_existing_evidence_object "$reference_id"); then
echo "Using existing Evidence Object: $evidence_id"
else
evidence_id=$(create_evidence_object "$reference_id" "$name" "$description" "$instructions" "$automated")
fi
# 3. Upload artifact with metadata
local title="$(echo "$mapping" | jq -r '.name') Results"
local note="Automated validation results from $script_name script executed on $(date -u +"%Y-%m-%d at %H:%M:%S UTC")"
upload_file_artifact "$evidence_id" "$script_output_file" "$title" "$note"
}
Key API Endpoints Used:
- GET /evidence - Retrieve all Evidence Sets to check for existing ones
- POST /evidence - Create new Evidence Set with metadata
- POST /evidence/{evidence_id}/artifacts/upload - Upload file artifacts with metadata
Authentication:
- Uses Bearer token authentication:
Authorization: Bearer $PARAMIFY_UPLOAD_API_TOKEN
- Token stored in
.envfile for security
Error Handling:
- Checks HTTP response codes (200, 201 for success)
- Handles "Reference ID already exists" errors gracefully
- Provides detailed error messages and logging
Comments
0 comments
Please sign in to leave a comment.