Integration GuidesGuide
Examples
Copyable cURL and TypeScript examples for the current Partner API, webhooks and laboratory contract.
On this page
Setup
export SOLIA_API_BASE="https://app.soliadirect.com/api/public/partner/v1"
export SOLIA_API_KEY="<key>"Important
There is no Solia SDK. These examples call the HTTP contract directly.
Programs and Catalog
curl -s "$SOLIA_API_BASE/programs" -H "Authorization: Bearer $SOLIA_API_KEY"
curl -s "$SOLIA_API_BASE/programs/$PROGRAM_ID/catalog" -H "Authorization: Bearer $SOLIA_API_KEY"
curl -s "$SOLIA_API_BASE/programs/$PROGRAM_ID/requirements?item_id=$ITEM_ID" -H "Authorization: Bearer $SOLIA_API_KEY"Serviceability
curl -s -X POST "$SOLIA_API_BASE/serviceability" \
-H "Authorization: Bearer $SOLIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"program_id":"'"$PROGRAM_ID"'","item_id":"'"$ITEM_ID"'"}'Create and simulate a Sandbox order
const base = process.env.SOLIA_API_BASE!;
const headers = {
Authorization: `Bearer ${process.env.SOLIA_API_KEY}`,
"Content-Type": "application/json",
};
export async function createOrder(programId: string, itemId: string, collection: string) {
const res = await fetch(`${base}/orders`, {
method: "POST",
headers: { ...headers, "Idempotency-Key": "order-1001" },
body: JSON.stringify({
external_order_id: "order-1001",
program_id: programId,
item_id: itemId,
external_subject_id: "subject-1001",
collection,
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error?.code} (request ${body.request_id})`);
return body.data;
}
export async function simulate(orderId: string) {
await fetch(`${base}/sandbox/orders/${orderId}/simulate`, {
method: "POST",
headers,
body: JSON.stringify({ scenario: "happy_path" }),
});
}Read order, results and events
curl -s "$SOLIA_API_BASE/orders/$ORDER_ID" -H "Authorization: Bearer $SOLIA_API_KEY"
curl -s "$SOLIA_API_BASE/orders/$ORDER_ID/results" -H "Authorization: Bearer $SOLIA_API_KEY"
curl -s "$SOLIA_API_BASE/events?limit=50" -H "Authorization: Bearer $SOLIA_API_KEY"Verify a webhook signature
import { createHmac, timingSafeEqual } from "node:crypto";
const seenDeliveries = new Set<string>();
export function verifySolia(rawBody: string, headers: Record<string, string>, secret: string): boolean {
const timestamp = Number(headers["x-solia-timestamp"]);
const presented = headers["x-solia-signature"] ?? "";
const deliveryId = headers["x-solia-delivery-id"];
if (!Number.isFinite(timestamp) || Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
const expected = "v1=" + createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
if (expected.length !== presented.length) return false;
if (!timingSafeEqual(Buffer.from(expected), Buffer.from(presented))) return false;
if (deliveryId && seenDeliveries.has(deliveryId)) return false;
if (deliveryId) seenDeliveries.add(deliveryId);
return true;
}Use durable storage instead of an in-memory set in production.
HTTPS/JSON laboratory endpoint
Your laboratory server receives POST <your base>/connection-test and POST <your base>/orders with X-Solia-Contract-Version: solia.lab.v1, X-Solia-Tenant-Id, X-Solia-Adapter-Key, X-Solia-Transmission-Id and Idempotency-Key. Respond 2xx within 15 seconds and deduplicate on the idempotency key.
Inbound lifecycle events are POSTed to /api/public/lab-events signed with X-Solia-Signature: v1=<hex HMAC-SHA256> over <X-Solia-Timestamp>.<raw body>. The exact body schema is published at /api/public/solia-lab-contract.
TS=$(date +%s)
SIG="v1=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$LAB_SIGNING_SECRET" -hex | sed 's/^.* //')"
curl -s -X POST "https://app.soliadirect.com/api/public/lab-events" \
-H "X-Solia-Timestamp: $TS" -H "X-Solia-Signature: $SIG" \
-H "Content-Type: application/json" --data "$BODY"