HTTP API
PichaFlow can be integrated into any language or framework that supports HTTP requests.
The PichaFlow Edge Engine is split into two specialized endpoints:
- Uploads:
https://egn.pichaflow.com/v1 - Asset Delivery & Transformations:
https://cdn.pichaflow.com
Authentication
All requests must include your Secret Key in the Authorization header as a Bearer token.
Authorization: Bearer sk_live_your_secret_key
Authorization header is required.Payload Limits & Pre-Optimization
To guarantee ultra-fast edge processing, the PichaFlow Edge Engine enforces a strict 5MB file size limit on all direct HTTP API uploads.
If you are uploading via a backend server (bypassing our frontend SDKs), you must compress your images down to a maximum of 2048px (ideally WebP) before making the POST request. Uploads exceeding 5MB will be rejected with a 413 Payload Too Large error.
Directory Organization
You can organize uploads into directories by including the optional directory field. The directory path becomes part of the asset's permanent delivery URL.
Rules:
- Directory names may only contain letters, numbers, hyphens, and underscores.
- Nested directories are supported (e.g.,
products/summer/2026/). - If
directoryis omitted, assets are stored at the project root. - Path traversal attempts (e.g.,
../) are automatically stripped.
1. Uploading Images (cURL)
curl -X POST https://egn.pichaflow.com/v1/upload \
-H "Authorization: Bearer sk_live_..." \
-F "file=@/path/to/your/image.jpg" \
-F "tenantId=pf_prj_your_id" \
-F "directory=products/hero" \
-F "alt=Description for SEO" \
-F "tags=[\"ecommerce\", \"summer\"]"
2. Python Integration
import requests
url = "https://egn.pichaflow.com/v1/upload"
headers = {
"Authorization": "Bearer sk_live_your_secret_key"
}
files = {
"file": open("product.jpg", "rb")
}
data = {
"tenantId": "pf_prj_your_id",
"directory": "products/boots",
"alt": "Summer Collection Boot",
"tags": "[\"ecommerce\"]"
}
response = requests.post(url, headers=headers, files=files, data=data)
print(response.json())
3. Node.js (Fetch)
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('tenantId', 'pf_prj_your_id');
formData.append('directory', 'furniture/sofas');
formData.append('alt', 'Modern Sofa');
const response = await fetch('https://egn.pichaflow.com/v1/upload', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_your_secret_key'
},
body: formData
});
const result = await response.json();
4. PHP Integration
$ch = curl_init('https://egn.pichaflow.com/v1/upload');
$cfile = new CURLFile('image.jpg', 'image/jpeg', 'file');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
'file' => $cfile,
'tenantId' => 'pf_prj_your_id',
'directory' => 'watches/luxury',
'alt' => 'Luxury Watch'
]);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer sk_live_your_secret_key'
]);
$result = curl_exec($ch);
curl_close($ch);
5. Go Integration
package main
import (
"bytes"
"io"
"mime/multipart"
"net/http"
"os"
)
func main() {
file, _ := os.Open("image.jpg")
defer file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, _ := writer.CreateFormFile("file", "image.jpg")
io.Copy(part, file)
writer.WriteField("tenantId", "pf_prj_your_id")
writer.WriteField("directory", "kitchen/mugs")
writer.WriteField("alt", "Coffee Mug")
writer.Close()
req, _ := http.NewRequest("POST", "https://egn.pichaflow.com/v1/upload", body)
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("Authorization", "Bearer sk_live_your_secret_key")
client := &http.Client{}
client.Do(req)
}
6. Rust Integration
use reqwest::header::{AUTHORIZATION, HeaderValue};
use reqwest::multipart;
use std::fs;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::new();
let file_path = "image.jpg";
let file_bytes = fs::read(file_path)?;
let form = multipart::Form::new()
.part("file", multipart::Part::bytes(file_bytes).file_name("image.jpg"))
.text("tenantId", "pf_prj_your_id")
.text("directory", "watches/titanium")
.text("alt", "Titanium Wristwatch")
.text("tags", "[\"luxury\", \"watch\"]");
let response = client
.post("https://egn.pichaflow.com/v1/upload")
.header(AUTHORIZATION, HeaderValue::from_static("Bearer sk_live_your_secret_key"))
.multipart(form)
.send()
.await?;
println!("Status: {}", response.status());
println!("Body: {}", response.text().await?);
Ok(())
}
7. URL Transformations (Image Retrieval)
Once your image is uploaded, the PichaFlow Edge Engine allows you to transform it on the fly by appending URL parameters to the asset's URL. The engine caches the result at the edge for ultra-low latency on subsequent requests.
Standard Transformations (Available on All Tiers)
These parameters can be used by all tenants, including the free Hobby tier.
| Parameter | Type | Description | Example |
|---|---|---|---|
w | Integer | Resizes the image to the specified width (1 - 5000px). | ?w=800 |
h | Integer | Resizes the image to the specified height (1 - 5000px). | ?h=600 |
q | Integer | Compression quality percentage (1 - 100). Default is 80. | ?q=90 |
f | String | Output format (avif, webp, png, jpg). Default is avif. | ?f=webp |
preset | String | A predefined configuration identifier for pipelines. | ?preset=thumbnail |
Advanced Compositing & Effects (Tier Gated)
Certain resource-intensive visual transformations require higher compute and are gated by your billing tier.
403 Forbidden response.| Parameter | Type | Minimum Tier | Description | Example |
|---|---|---|---|---|
ck | String | Pro | Chroma-Keying. Removes the specified hex color background. | ?ck=00FF00 |
wm | String | Scale | Watermarking. Overlays an asset (must exist in your namespace). | ?wm=logo.png |
crop | String | Scale | Coordinates (x,y,w,h) or gravity strings (center, top). | ?crop=center |
Example Usage
<!-- Asset at project root -->
<img src="https://cdn.pichaflow.com/pf_prj_your_id/product.jpg?w=800&q=90" />
<!-- Asset inside a directory (directory path is part of the URL) -->
<img src="https://cdn.pichaflow.com/pf_prj_your_id/products/hero/product.jpg?w=800&q=90" />
<!-- Pro Tier: Removes green screen background -->
<img src="https://cdn.pichaflow.com/pf_prj_your_id/products/hero/product.jpg?ck=00FF00" />
<!-- Scale Tier: Overlays a watermark -->
<img src="https://cdn.pichaflow.com/pf_prj_your_id/products/hero/product.jpg?wm=logo.png&w=1200" />
<!-- Scale Tier: Crops a specific 200x200 region -->
<img src="https://cdn.pichaflow.com/pf_prj_your_id/products/hero/product.jpg?crop=50,50,200,200" />
<!-- Scale Tier: Crops a perfect square from the center -->
<img src="https://cdn.pichaflow.com/pf_prj_your_id/products/hero/product.jpg?crop=center" />
8. Dynamic OG Generation (Pro+)
PichaFlow provides a dedicated API endpoint to automatically generate polished OpenGraph (social sharing) cards for your products, blog posts, or profiles.
/v1/og-generator deducts 2 transformation credits from your quota. This feature requires the Pro tier or higher.Endpoint
GET https://cdn.pichaflow.com/v1/og-generator
Parameters
| Parameter | Required | Description | Example |
|---|---|---|---|
img | Yes | The full path to the raw product/background image in your namespace. | ?img=pf_prj_id/sneaker.jpg |
title | Yes | The main heading text for the card (URL encoded). | ?title=Air%20Max%2090 |
price | No | Optional price or secondary subtitle text. | ?price=$120.00 |
logo | No | Path to a custom logo asset in your namespace. | ?logo=pf_prj_id/brand/logo.png |
theme | No | UI color theme: dark (default) or light. | ?theme=dark |
accent | No | Hex code for the gradient accent color (without #). | ?accent=3b82f6 |
font | No | Typography choice (Inter, Roboto, Outfit). Default Inter. | ?font=Outfit |
Example Request
<meta property="og:image" content="https://cdn.pichaflow.com/v1/og-generator?img=pf_prj_id/products/sneaker.jpg&title=Air%20Max%2090&price=$120.00&theme=dark&accent=ff3366" />
9. Deleting Assets Programmatically
You can delete assets securely using your Secret Key. When an asset is deleted, it is instantly purged from the global edge cache, physically removed from your storage bucket, and your project's usage quota is immediately updated.
Single Deletion
Delete a single asset by its UUID.
curl -X DELETE https://egn.pichaflow.com/v1/assets/your-asset-uuid \
-H "Authorization: Bearer sk_live_your_secret_key"
Bulk Deletion
Delete multiple assets at once by sending an array of UUIDs. This is highly recommended for cleaning up galleries or user accounts.
curl -X POST https://egn.pichaflow.com/v1/assets/delete \
-H "Authorization: Bearer sk_live_your_secret_key" \
-H "Content-Type: application/json" \
-d '{"ids": ["uuid-1", "uuid-2", "uuid-3"]}'
10. Client-Side Upload Signatures
If you are uploading assets directly from a frontend application (e.g., a React or Vue app), you must not expose your Secret Key in client code. Instead, PichaFlow uses short-lived HMAC-SHA256 upload signatures with cryptographically bound constraints to prevent replay attacks, directory hijacking, oversized payloads, and unapproved file types.
How it Works
Your backend server generates a signed context and returns it to the frontend. The frontend then attaches all five headers to the upload request, which the PichaFlow Edge Engine validates independently — without a database round-trip.
┌──────────────┐ 1. Request signature ┌──────────────────┐
│ Frontend │ ─────────────────────────► │ Your Backend │
│ (Browser) │ ◄───────────────────────── │ (Sign Endpoint) │
└──────────────┘ 2. { signature, └──────────────────┘
timestamp, │
directory, Computes HMAC-SHA256 over:
maxSize, "upload:tenantId:timestamp
allowedTypes } :directory:maxSize:allowedTypes"
│
3. POST /v1/upload (file + all 5 headers)
▼
┌──────────────────────┐
│ PichaFlow Engine │
│ egn.pichaflow.com │
│ ✓ Validates HMAC │
│ ✓ Checks timestamp │
│ ✓ Checks file size │
│ ✓ Checks MIME type │
│ ✓ Checks directory │
└──────────────────────┘
Required Headers
All five headers are required when using signature-based auth (i.e., when not using a Secret Key):
| Header | Type | Description |
|---|---|---|
X-Picha-Signature | String | HMAC-SHA256 hex digest, signed with your Secret Key. |
X-Picha-Timestamp | Number | Unix epoch in milliseconds when the signature was created. Signatures expire after 60 seconds. |
X-Picha-Directory | String | The upload destination directory (e.g. / or products/summer/). Must match the signed value exactly. |
X-Picha-Max-Size | Number | Maximum permitted file size in bytes. The engine rejects uploads larger than this value. |
X-Picha-Allowed-Types | String | Comma-separated list of permitted MIME types (e.g. image/webp,image/jpeg). Use */* to allow all. |
HMAC Construction
For security, signatures must be generated by the PichaFlow API Engine using an internal token. Your backend acts as a secure proxy that authenticates with your Secret Key, forwards the constraints to PichaFlow, and returns the generated signature payload to your frontend.
Example (Node.js Proxy Endpoint):
// server/routes/api/upload/sign.js
export default defineEventHandler(async (event) => {
// 1. Authenticate the caller (ensure they are logged in to your app)
const session = await getUserSession(event);
if (!session?.user) throw createError({ statusCode: 401 });
const tenantId = session.user.tenantId;
// 2. Read the constraint intent from the incoming frontend request
const directory = getHeader(event, 'x-picha-directory') || '/';
const maxSize = getHeader(event, 'x-picha-max-size') || '5242880'; // 5MB default
const allowedTypes = getHeader(event, 'x-picha-allowed-types')|| 'image/webp,image/jpeg';
// 3. Request the signature from the PichaFlow API Engine
const pichaRes = await fetch('https://api.pichaflow.com/v1/upload/sign', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.PICHAFLOW_SECRET_KEY}`, // Your sk_live_ key
'x-picha-directory': directory,
'x-picha-max-size': maxSize,
'x-picha-allowed-types': allowedTypes
}
});
if (!pichaRes.ok) {
throw createError({ statusCode: pichaRes.status, statusMessage: 'Failed to generate signature' });
}
// 4. Return the complete signature payload to the frontend
return await pichaRes.json();
});
Frontend Upload (JavaScript)
async function secureUpload(file) {
// 1. Request a signed context from your backend, passing the upload constraints
const intent = await fetch('/api/upload/sign', {
method: 'POST',
headers: {
'x-picha-directory': 'products/summer/',
'x-picha-max-size': String(file.size),
'x-picha-allowed-types': 'image/webp,image/jpeg',
}
}).then(r => r.json());
// 2. Build the form data payload
const formData = new FormData();
formData.append('file', file);
formData.append('tenantId', intent.tenantId);
formData.append('directory', intent.directory);
// 3. POST directly to the Edge Engine with all 5 constraint headers
const response = await fetch('https://egn.pichaflow.com/v1/upload', {
method: 'POST',
headers: {
'X-Picha-Signature': intent.signature,
'X-Picha-Timestamp': String(intent.timestamp),
'X-Picha-Directory': intent.directory,
'X-Picha-Max-Size': intent.maxSize,
'X-Picha-Allowed-Types': intent.allowedTypes,
},
body: formData,
});
return response.json();
}
@pichaflow/react, @pichaflow/vue, @pichaflow/svelte, etc.) handle signature generation and header injection automatically when you configure the signatureUrl option. The manual implementation above is only required for custom integrations.