API Reference

The ProofMark REST API lets you create, manage, and verify digital product passports at scale — from single products to batches of 1,000+.

Overview

All API requests use JSON. Responses always include a success boolean field. On failure, a message field describes the error.

Base URL: https://proofmark-8ww4.polsia.app

Authentication

All write endpoints and admin read endpoints require a valid session token obtained via the admin login. Pass the token as a cookie (pm_auth) or as a Bearer token in the Authorization header.

http
Authorization: Bearer <your-token>

Obtain a Token

POST /api/auth/login Authenticate with admin password

Submit your admin password to receive a session token (valid 7 days). The token is also set as an httpOnly cookie automatically.

json — request body
{
  "password": "your-admin-password"
}
json — 200 response
{
  "success": true
}

Create Passport

POST /api/passports Create a new product passport

Creates a passport with a unique PM-XXXXXXXX ID and automatically generates a QR code pointing to the public verification page.

Request Body

FieldTypeRequiredDescription
product_namestringrequiredName of the product
materialsstring[]optionalArray of material names (e.g. ["Organic Cotton", "Recycled Polyester"])
originstringoptionalCountry or region of manufacture
manufacturerstringoptionalManufacturer name
dpp_statusstringoptionalDPP compliance status. Default: "compliant"
sustainability_scorestringoptionalSustainability rating A–F. Default: "A"
batch_idstringoptionalBatch or lot identifier for grouping
metadataobjectoptionalCustom key-value data
curl
curl -X POST https://proofmark-8ww4.polsia.app/api/passports \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "product_name": "Luxury Tote Bag",
    "materials": ["Full-Grain Leather", "Brass Hardware"],
    "origin": "Italy",
    "manufacturer": "Atelier Milano",
    "dpp_status": "compliant",
    "sustainability_score": "B",
    "batch_id": "BATCH-2026-Q1"
  }'
json — 201 response
{
  "success": true,
  "passport": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "passport_id": "PM-A3F81C2B",
    "product_name": "Luxury Tote Bag",
    "materials": ["Full-Grain Leather", "Brass Hardware"],
    "origin": "Italy",
    "manufacturer": "Atelier Milano",
    "dpp_status": "compliant",
    "sustainability_score": "B",
    "batch_id": "BATCH-2026-Q1",
    "qr_code": "data:image/png;base64,...",
    "verify_url": "https://proofmark-8ww4.polsia.app/verify/PM-A3F81C2B",
    "created_at": "2026-03-17T10:50:00Z"
  }
}

List Passports

GET /api/passports List passports with pagination & search

Query Parameters

ParameterTypeDescription
searchstringSearch by product name, passport ID, or manufacturer
batch_idstringFilter by batch ID
limitintegerMax results per page (default: 50, max: 1000)
offsetintegerPagination offset (default: 0)
json — 200 response
{
  "success": true,
  "passports": [ /* array of passport objects */ ],
  "total": 142,
  "limit": 50,
  "offset": 0
}

Get Passport

GET /api/passports/:id Get a single passport by ID

Retrieve a passport by its passport_id (e.g. PM-A3F81C2B) or internal UUID.

curl
curl https://proofmark-8ww4.polsia.app/api/passports/PM-A3F81C2B \
  -H "Authorization: Bearer <token>"

Update Passport

PATCH /api/passports/:id Update passport fields

Partial updates — only include fields you want to change. All fields from Create Passport are accepted except passport_id (immutable).

curl
curl -X PATCH https://proofmark-8ww4.polsia.app/api/passports/PM-A3F81C2B \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "sustainability_score": "A" }'

Delete Passport

DELETE /api/passports/:id Permanently delete a passport

This action is irreversible. The QR code will stop resolving to a valid verification page.

json — 200 response
{ "success": true, "message": "Passport deleted" }

Download QR Code

GET /api/passports/:id/qr Download QR as PNG file

Returns a PNG image for download. The QR code encodes the public verification URL for that passport.

ParameterDescription
?sizeImage size in pixels (50–600). Default: 400
curl
curl -o PM-A3F81C2B-qr.png \
  "https://proofmark-8ww4.polsia.app/api/passports/PM-A3F81C2B/qr?size=400" \
  -H "Authorization: Bearer <token>"

Bulk QR Export

GET /api/passports/qr/bulk Download QR codes as ZIP

Returns a ZIP archive containing one PNG per passport. Supports up to 1,000 QR codes per request.

ParameterDescription
?idsComma-separated list of passport IDs. Omit to export all.
?batch_idExport all passports in a batch.
curl
# Export specific passports
curl -o qr-codes.zip \
  "https://proofmark-8ww4.polsia.app/api/passports/qr/bulk?ids=PM-A3F81C2B,PM-B4C92D3E" \
  -H "Authorization: Bearer <token>"

# Export entire batch
curl -o qr-codes.zip \
  "https://proofmark-8ww4.polsia.app/api/passports/qr/bulk?batch_id=BATCH-2026-Q1" \
  -H "Authorization: Bearer <token>"

Import Passports

POST /api/passports/import Bulk import up to 1,000 passports

Import passports from a CSV file or JSON array. QR codes are auto-generated for all imported passports.

CSV Format

First row must be a header row with column names matching the passport fields.

csv
product_name,materials,origin,manufacturer,dpp_status,sustainability_score,batch_id
Leather Wallet,"Full-Grain Leather,Cotton Lining",Italy,Atelier Milano,compliant,A,BATCH-Q1
Canvas Tote,"Organic Cotton,Brass Hardware",Portugal,Porto Fabrics,compliant,B,BATCH-Q1

JSON Format

curl
curl -X POST https://proofmark-8ww4.polsia.app/api/passports/import \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "passports": [{ "product_name": "Sneaker", "origin": "Portugal" }] }'
json — 200 response
{
  "success": true,
  "imported": 250,
  "failed": 0,
  "passports": [ /* array of created passport objects */ ]
}

Stats Overview

GET /api/passports/stats/overview Passport statistics
json — 200 response
{
  "success": true,
  "stats": {
    "total_passports": 1420,
    "compliant": 1380,
    "recent_7d": 84
  }
}

Verify Product

GET /verify/:passportId Public verification page — no auth

This is the URL encoded in every QR code. Returns a branded HTML verification page showing product details, materials, DPP status, and sustainability score.

Public endpoint. No authentication required — this is what end consumers see when they scan a QR code.
example
https://proofmark-8ww4.polsia.app/verify/PM-A3F81C2B

Capture Lead

POST /api/leads Submit a prospect email — no auth

Used by the ProofMark landing page. Deduplicates by email. Triggers an email notification to the admin.

json — request body
{
  "email": "brand@example.com",
  "company_name": "Atelier Milano",
  "source": "landing"
}

Passport Object Schema

The full passport object returned by create, get, and list endpoints.

id uuid Internal UUID primary key. Immutable.
passport_id string User-facing ID in format PM-XXXXXXXX. Auto-generated. Immutable.
product_name string Display name of the product. Max 500 chars.
materials string[] Array of material names. Supports EU DPP materials disclosure requirement.
origin string | null Country or region of manufacture (e.g. "Italy", "Portugal").
manufacturer string | null Manufacturer or factory name.
dpp_status string EU Digital Product Passport compliance status. Values: compliant, pending, non-compliant.
sustainability_score string Sustainability rating from A (best) to F (worst).
batch_id string | null Batch or lot identifier. Use for grouping passports and bulk QR export.
metadata object Arbitrary key-value store for custom fields (certifications, SKUs, etc.).
qr_code string Base64 data URL of the QR code PNG. Available on create response only.
verify_url string Public verification URL for this passport. Encoded in the QR code.
created_at timestamp ISO 8601 creation timestamp.
updated_at timestamp ISO 8601 last-updated timestamp.

Error Codes

All errors return a success: false response with a human-readable message.

StatusDescription
400 Bad RequestMissing required fields (e.g. product_name not provided)
401 UnauthorizedMissing or invalid authentication token
404 Not FoundPassport ID does not exist
429 Too Many RequestsRate limit exceeded (import endpoint caps at 1,000 records)
500 Internal Server ErrorUnexpected server error

Shopify Integration

Auto-create a ProofMark passport whenever a new product is added in Shopify using Shopify Webhooks.

javascript — shopify webhook handler
// In your Shopify app or webhook handler:
app.post('/webhooks/shopify/product-created', async (req, res) => {
  const product = req.body;

  const response = await fetch('https://proofmark-8ww4.polsia.app/api/passports', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.PROOFMARK_TOKEN}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      product_name: product.title,
      materials: product.tags?.split(',') || [],
      origin: product.vendor,
      metadata: {
        shopify_product_id: product.id,
        shopify_handle: product.handle
      }
    })
  });

  const passport = await response.json();
  // Store passport.passport.verify_url in your product metafields
  // Print passport.passport.qr_code to packaging
  res.json({ success: true });
});

WooCommerce Integration

Use WooCommerce's product save hooks to create passports automatically.

php — functions.php
add_action('woocommerce_new_product', 'create_proofmark_passport');

function create_proofmark_passport($product_id) {
    $product = wc_get_product($product_id);

    $response = wp_remote_post('https://proofmark-8ww4.polsia.app/api/passports', [
        'headers' => [
            'Authorization' => 'Bearer ' . get_option('proofmark_api_token'),
            'Content-Type'  => 'application/json'
        ],
        'body' => json_encode([
            'product_name'  => $product->get_name(),
            'manufacturer'  => $product->get_attribute('manufacturer'),
            'origin'        => $product->get_attribute('origin'),
            'metadata'      => ['woo_id' => $product_id]
        ])
    ]);

    $passport = json_decode(wp_remote_retrieve_body($response));
    update_post_meta($product_id, '_proofmark_passport_id', $passport->passport->passport_id);
    update_post_meta($product_id, '_proofmark_verify_url', $passport->passport->verify_url);
}

ERP / Bulk Import

For large product catalogs, use the bulk import endpoint with a CSV export from your ERP or PIM system.

python — bulk import script
import requests
import csv

TOKEN = "your-proofmark-token"
BASE = "https://proofmark-8ww4.polsia.app"

# Load product data from ERP export
with open("products.csv") as f:
    reader = csv.DictReader(f)
    products = list(reader)

# Send in batches of 1,000
for i in range(0, len(products), 1000):
    batch = products[i:i+1000]
    res = requests.post(
        f"{BASE}/api/passports/import",
        headers={"Authorization": f"Bearer {TOKEN}"},
        json={"passports": batch}
    )
    data = res.json()
    print(f"Batch {i//1000 + 1}: imported {data['imported']}, failed {data['failed']}")

Ready to get started?

Create your first product passport in seconds. No hardware required.

Start Free Trial →