Authentication
Priostack uses API keys for authentication. Every workflow API request must include a valid API key. Keys are tied to a specific account and carry the credit balance for that account.
Base URL
There is one origin, https://priostack.com. Engine routes live under /api/v1/ (process definitions, process instances, jobs, incidents, models, cases, decisions, tasks, GraphQL, webhooks, workers). Account and billing routes live under /api/ with no version: /api/me, /api/credits, /api/credits/packs, /api/wallet, /api/usage. No other host name and no alias path serves the API: /v1/..., /graphql, /api/v1/deployments, /api/v1/definitions and /api/v1/instances answer an error. A BPMN modeler cannot deploy here from its own Deploy button, because no route serves a modeler's deploy: save the .bpmn file and upload it with POST /api/v1/process-definitions and your API key.
Getting Your API Key
- Sign up with your email address. The key is withheld until you confirm the address.
- Confirm the address from the email you receive: the welcome email that follows carries your API key.
- Signed in, you can show the full key again or rotate it at any time in Creator Studio, under API credentials.
GET /api/meonly ever returns it masked. - New accounts receive 100 free credits at signup, then 100 more for each full day, with no card required.
POST /api/keys/rotate.
Using Your API Key
Include your API key in every request using the X-API-Key header. Authorization: Bearer <key> is accepted as well on almost every route. Two exceptions: the webhook routes (/api/v1/webhooks) accept only the X-API-Key header, and the task routes (/api/v1/tasks) accept X-API-Key or ?api_key= but not Bearer. Treat the key as an opaque string and do not check its length: three formats are live. A key issued at signup or by rotation is ps_ followed by 64 hexadecimal characters; an account the site made on first use of the wallet, billing or the dashboard, for someone who signed in without a developer account (with Google, for example), has ps_ followed by 32; a key reissued by Priostack support is prio_ followed by 48. All three work the same way on every route.
curl
curl -X POST https://priostack.com/api/v1/process-instances \
-H "X-API-Key: ps_your_key_here" \
-H "Content-Type: application/json" \
-d '{"bpmnProcessId": "order-processing", "variables": {"orderId": "123"}}'
Query Parameter (alternative)
If you cannot set headers (e.g., webhook testing), you can pass the key as a query parameter:
curl "https://priostack.com/api/v1/process-instances?api_key=ps_your_key_here" \
-X POST -H "Content-Type: application/json" \
-d '{"bpmnProcessId": "order-processing"}'
api_key query parameter in production - URLs may be logged in server access logs, browser history, and HTTP referrer headers.
Go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
func main() {
apiKey := os.Getenv("PRIOSTACK_API_KEY")
body, _ := json.Marshal(map[string]interface{}{
"bpmnProcessId": "order-processing",
"variables": map[string]interface{}{
"orderId": "ORD-001",
"amount": 149.99,
},
})
req, _ := http.NewRequest("POST",
"https://priostack.com/api/v1/process-instances",
bytes.NewReader(body))
req.Header.Set("X-API-Key", apiKey)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusCreated { // a started instance answers 201
fmt.Println("Error:", resp.Status, string(out))
return
}
fmt.Println("Started:", string(out))
}
Python
import os
import requests
api_key = os.environ["PRIOSTACK_API_KEY"]
base_url = "https://priostack.com"
headers = {
"X-API-Key": api_key,
"Content-Type": "application/json",
}
response = requests.post(
f"{base_url}/api/v1/process-instances",
headers=headers,
json={
"bpmnProcessId": "order-processing",
"variables": {
"orderId": "ORD-001",
"amount": 149.99,
}
}
)
response.raise_for_status() # 201 Created on success
print(response.json())
JavaScript (Node.js)
const apiKey = process.env.PRIOSTACK_API_KEY;
const baseUrl = "https://priostack.com";
const response = await fetch(`${baseUrl}/api/v1/process-instances`, {
method: "POST",
headers: {
"X-API-Key": apiKey,
"Content-Type": "application/json",
},
body: JSON.stringify({
bpmnProcessId: "order-processing",
variables: {
orderId: "ORD-001",
amount: 149.99,
},
}),
});
if (!response.ok) {
throw new Error(`start failed: ${response.status} ${await response.text()}`);
}
const data = await response.json();
console.log(data.processInstanceKey);
Short-lived Tokens and Key Rotation
POST /api/token with {"api_key": "ps_..."} returns an access_token valid for 30 minutes, to send as Authorization: Bearer; POST /api/token/refresh renews it. The token carries the same full authority as the key, so it only shortens exposure: mint it on a server. POST /api/keys/rotate, sent with the current key, replaces the key and returns {"new_key": "ps_..."}; the old key stops working at once.
Calling from a Browser
The REST API sends no CORS headers, so a web page on another origin cannot read its responses. Call it from your own backend and keep the key there. The agent network at /mcp is the one endpoint that answers CORS; it authenticates with agent tokens, not API keys (see Agent Context Network).
Security Best Practices
| Practice | Details |
|---|---|
| Use environment variables | Store your API key in an environment variable (e.g., PRIOSTACK_API_KEY), never hardcode it in source files. |
| Never commit to git | Add .env to your .gitignore. Use secret scanning tools (e.g., git-secrets, GitHub secret scanning). |
| Rotate regularly | Rotate your API key quarterly, or immediately if you suspect it has been exposed. |
| Use HTTPS only | Always call https://priostack.com. A key sent over plain HTTP can be read in transit. |
| Keep the key on a server | A key has full authority over its account: it can start work that spends credits and read every instance. Never ship it to a browser or a mobile app. |
Key Scopes
Keys are not scoped today: every API key, and every token minted from it, has full access to its account. If a service should only do part of the work, keep the key in one backend you control and let that backend call Priostack on the service's behalf.
Verify Your Key
Call GET /api/me to verify your key is valid and check your current credit balance:
curl https://priostack.com/api/me \
-H "X-API-Key: ps_your_key_here"
# Response:
{
"user_id": "you@company.com",
"api_key": "ps_1a2b3...9f0e",
"balance": 187,
"plan": "builder",
"created_at": "2026-09-01T10:00:00Z",
"workflow_endpoint": "https://priostack.com/api/v1"
}
user_id is the account's sign-in email address and balance is in credits. api_key is always masked here. plan is a label computed from the balance (sandbox at 100 credits or less, builder above), not a subscription. An unknown or disabled key answers 401 {"error":"unknown or disabled api key"}.