Prompier
Developers

Developers

Two ways to use your library outside the app: connect a developer AI tool such as Claude Code or Cursor over MCP, or read it from your own code with the REST API.

MCP server

Use your approved prompts, skills and apps from a developer AI tool over MCP: Claude Code, Cursor, VS Code or Claude Desktop. Available on the Individual and Team plans.

What is MCP? The Model Context Protocol is an open standard that lets an AI tool connect to other apps and use what they hold. Prompier works as an MCP server: your tool connects with a read-only key, finds your prompts, skills and apps by name, and runs them on your own subscription. In the app this is called AI tool access.

Setup

  1. In the app, open Settings › Connect an AI tool. In a team, an owner or admin must first switch AI tool access on for the workspace.
  2. Choose Create key, give it a name and an expiry. The key is read-only and works in that workspace only. It is shown once, so copy it now.
  3. Paste the setup snippet for your tool (below, with your own key in place of the example), then restart the tool.
  4. Ask your tool to run something by name, as in the examples under What it can do.
claude mcp add --transport http prompier https://prompier.com/mcp \ --header "Authorization: Bearer pmm_xxxxxxxx..."

Run this in your terminal.

MCP server URL: https://prompier.com/mcp

The address and key above are examples. Use the key you created: it starts with pmm_. Treat it like a password and do not share it or commit it to source control.

What it can do

Ask your tool for a prompt, a skill or an app by name. It finds the item, asks you for any missing answers, and builds the finished text. Your tool then runs it on your own subscription.

// prompt
run prompier prompt "weekly update", topic: spring launch
// skill
use prompier skill "release notes"
// app
run prompier app "launch brief", topic: spring launch
  • The prompt is built by us, and run by your tool. We never call an AI model for this and we store nothing you type or get back.
  • Each prompt you run counts as a use in Analytics, shown as "AI tool (MCP)".
  • Teams: approved prompts, skills and published apps only, for every role. Never drafts or history.
  • Personal workspaces: prompts marked Ready, and published apps.
  • Apps run step by step in your tool, and the answer of each step is passed to the next.

Limits

  • Plans: not included in Free. Included in Individual (you switch it on for your workspace) and in Team during the trial and when subscribed (an owner or admin switches it on for the workspace; it is off by default). A team that is read-only is paused and works again when it renews.
  • Read-only. Your tool can read and build prompts, skills and apps, never change them.
  • Review checkpoints in apps depend on your AI tool following the instructions, so they are best effort. In the web app they are enforced.
  • No Word, Excel or letterhead downloads over an AI tool. Use the app on the web for those.
  • Apps that need named approvers at a checkpoint run only in the web app.
  • Results are not saved or shared by us. The answer stays in your tool.
  • 120 calls a minute per key.
  • Developer AI tools only. This is for the tools listed above, using your own AI tool account.

Keys and safety

  • A connection key belongs to one person in one workspace. For another workspace, create a key there.
  • Keys expire after 90 days by default. You can choose 30 days, 1 year or never, and you can have up to 10 per person in each workspace.
  • A key stops working when its owner leaves the workspace, or when it expires or is revoked. Revoke a key in Settings at any time.
  • Changing your password does not revoke a key, so revoke it yourself if you lose a device.
  • We email you whenever a key is created, so a key you did not make gets noticed.
  • Team owners and admins can see everyone's keys (names and dates only, never a key) and revoke them.
  • Approved prompts run inside your own AI tool, with whatever access that tool has, such as files or other connectors.
Connection keys are different from REST API keys. Connection keys are for using prompts inside an AI tool. API keys (Team plan) are for your own code, see the REST API.

Messages you may see

Your AI tool may show one of these in plain words.

MessageWhat it means
Needs a paid planThe workspace is on the Free plan. Upgrade to Individual or Team.
Your team has not turned on AI tool accessAsk an owner or admin to switch it on in Settings › Connect an AI tool.
This team is read-only until it subscribesThe team's trial or subscription has ended. It works again when the team renews, with no need to reconnect.
You no longer have accessYou were removed from the workspace, so your keys no longer work there.
The connection does not work at allThe key has expired or was revoked. Create a new key and update your tool.

REST API

For your own apps, automations and scripts. Version 1 · base URL https://prompier.com/v1 · Team plan. Read your team's prompts and the app results your team shares, and run your live apps. Machine-readable description: OpenAPI spec (import it into Postman, a code generator or an AI agent).

Authentication

The REST API is part of the Team plan. Create a key in Settings › API keys (owners and admins can) and send it with every request in the Authorization header. Keys belong to the workspace, not to the person who made them, so they keep working when people leave. The exception is a key that can run apps: it runs as the person who made it and is revoked when that person leaves or stops being an owner or admin. A key is shown once: store it in a secret manager and never commit it to source control. Call the API from your servers only; it does not allow requests from web pages.

# Check your key and see which workspace it belongs to curl https://prompier.com/v1/me \ -H "Authorization: Bearer pm_live_..."
Python
import os, requests API = "https://prompier.com/v1" headers = {"Authorization": f"Bearer {os.environ['PROMPIER_API_KEY']}"} print(requests.get(f"{API}/me", headers=headers).json())
JavaScript
const headers = { Authorization: `Bearer ${process.env.PROMPIER_API_KEY}` }; const res = await fetch("https://prompier.com/v1/me", { headers }); console.log(await res.json());

Each key has scopes and an expiry (30 days, 90 days, 1 year or never; 90 days is the default). Revoke a key at any time and it stops working immediately. A workspace can hold up to 10 active keys.

ScopeAllows
read:promptsList and read prompts, and render them.
read:versionsRead a prompt's version history.
read:resultsRead the app results your team shared. Off by default, because results can hold sensitive text.
run:appsRun your live apps and read those runs. Off by default, because runs spend your team's AI budget.

What a key can see

Your team's review rules apply to the API too. When you create a key you choose how much it may read:

  • Approved prompts only (default, recommended for production). The key reads exactly what a team viewer sees: each prompt's approved version, its approved title, description and tags. Drafts, prompts that were never approved and archived prompts are not visible, and an unapproved version cannot be reached by number or label.
  • Include drafts (for staging or internal tools). The key can also read draft text, every version and every label. Archived prompts are never returned.

Without ?label or ?version, a request returns the approved version. Prompts are written and approved in Prompier, so nothing you call here can change them.

Rate limits

Each API key may make 300 requests per minute. Every response includes the headers below so you can back off before you hit the limit; a request over the limit gets a 429 with Retry-After.

Headers: X-RateLimit-Limit, X-RateLimit-Remaining and Retry-After (seconds, sent with 429 responses).

Endpoints

A prompt has an id, a stable slug, a body with {{variables}}, and numbered versions. Wherever an endpoint takes {prompt}, pass either the slug or the id. Teams mark the signed-off version with the label approved.

Check a key

GET /v1/me

Returns the workspace, the key's name, scopes, access level and expiry, and the rate limit. No prompt data. Use it to confirm a key works.

{ "workspace": { "id": "0198f2c4-...", "name": "Acme Marketing" }, "key": { "name": "Website", "prefix": "pm_live_8f3a", "scopes": ["read:prompts"], "access": "approved", "expires_at": "2027-01-11T09:30:00Z" }, "rate_limit": { "requests_per_minute": 300 } }

List prompts

GET /v1/prompts

Query parameters: q (search), kind (prompt, the default, skill or all), folder (folder id), tag, status (keys that include drafts only), limit (1 to 100, default 25) and cursor. Newest first. When there are more results, next_cursor is set: pass it back as cursor to get the next page.

curl "https://prompier.com/v1/prompts?tag=email&limit=20" \ -H "Authorization: Bearer $PROMPIER_API_KEY"
Python
r = requests.get(f"{API}/prompts", headers=headers, params={"tag": "email", "limit": 20}) for p in r.json()["data"]: print(p["slug"], p["version"])
JavaScript
const url = new URL("https://prompier.com/v1/prompts"); url.search = new URLSearchParams({ tag: "email", limit: "20" }); const { data, next_cursor } = await (await fetch(url, { headers })).json();

Response

{ "data": [ { "id": "0198f2c4-7b1e-7d2a-9c3e-5a1f0e8b6d42", "kind": "prompt", "slug": "weekly-newsletter-intro", "title": "Weekly newsletter intro", "description": "Drafts the weekly customer newsletter intro. Fill in the audience and topic.", "status": "approved", "tags": ["email"], "folder_id": null, "version": 6, "approved_version": 6, "updated_at": "2026-10-09T14:12:03Z" } ], "next_cursor": null }

Get a prompt

GET /v1/prompts/{prompt}

Returns the approved version. Add ?label=production for the version carrying another label (every team has approved, production and staging; owners and admins manage the others under Settings, API), or ?version=4 for a specific version (keys that include drafts can read any version; approved-only keys can read only the approved one).

curl "https://prompier.com/v1/prompts/weekly-newsletter-intro" \ -H "Authorization: Bearer $PROMPIER_API_KEY"
Python
prompt = requests.get(f"{API}/prompts/weekly-newsletter-intro", headers=headers).json() print(prompt["body"])
JavaScript
const prompt = await (await fetch("https://prompier.com/v1/prompts/weekly-newsletter-intro", { headers })).json();

Response

{ "id": "0198f2c4-7b1e-7d2a-9c3e-5a1f0e8b6d42", "kind": "prompt", "slug": "weekly-newsletter-intro", "title": "Weekly newsletter intro", "description": "Drafts the weekly customer newsletter intro. Fill in the audience and topic.", "status": "approved", "tags": ["email"], "folder_id": null, "updated_at": "2026-10-09T14:12:03Z", "approved_version": 6, "version": 6, "labels": ["approved"], "body": "Write a friendly newsletter intro for {{audience}} about {{topic}}.", "system_prompt": null, "variables": [ { "name": "audience", "type": "text", "default": "", "required": true, "options": [], "hint": "Who will read this?", "example": "Remote team leads" }, { "name": "topic", "type": "text", "default": "", "required": true, "options": [] } ], "version_created_at": "2026-10-09T14:12:03Z" }

A variable may carry a hint (what to enter) and an example when its author wrote them. They are help text for whoever fills the variable in: send your own values when you render, an example is never used as a value.

If the prompt uses shared snippets, body_expanded (and system_prompt_expanded) hold the text with the snippets filled in.

Render with variables

POST /v1/prompts/{prompt}/render

Returns the final text with your values filled in, ready to send to a model. It changes nothing in Prompier. Send values, and optionally label or version (same rules as above). Missing required variables return a 422 that lists them.

curl -X POST "https://prompier.com/v1/prompts/weekly-newsletter-intro/render" \ -H "Authorization: Bearer $PROMPIER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"values": {"audience": "small business owners", "topic": "our spring launch"}}'
Python
r = requests.post( f"{API}/prompts/weekly-newsletter-intro/render", headers=headers, json={"values": {"audience": "small business owners", "topic": "our spring launch"}}, ) text = r.json()["text"] # send this to your model
JavaScript
const res = await fetch("https://prompier.com/v1/prompts/weekly-newsletter-intro/render", { method: "POST", headers: { ...headers, "Content-Type": "application/json" }, body: JSON.stringify({ values: { audience: "small business owners", topic: "our spring launch" } }), }); const { text } = await res.json();

Response

{ "text": "Write a friendly newsletter intro for small business owners about our spring launch.", "system": null, "version": 6 }

Get a skill

GET /v1/prompts/{prompt}/skill.md

A skill is plain instructions with a name and a description, kept next to your prompts. List them with ?kind=skill (or kind=all for both), and read one with the same endpoint as a prompt: it comes back with "kind": "skill", its description, the instructions in body and the finished file in skill_md. This endpoint returns that file as text/markdown, ready to save as SKILL.md in a folder named after the skill. The same version rules apply: the approved version by default, ?label and ?version for keys that include drafts. A skill has no variables, so /render returns a 422 for it, and this endpoint returns a 422 for a prompt.

curl "https://prompier.com/v1/prompts/meeting-notes-summarizer/skill.md" \ -H "Authorization: Bearer $PROMPIER_API_KEY" -o SKILL.md

Versions

GET /v1/prompts/{prompt}/versions

Needs the read:versions scope. Newest first, with labels and timestamps. Keys that include drafts also get each version's change note; approved-only keys see just the approved version. Read a version's text with GET /v1/prompts/{prompt}?version=N.

{ "data": [ { "number": 6, "approved": true, "labels": ["approved"], "created_at": "2026-10-09T14:12:03Z", "change_note": "Shorter intro" }, { "number": 5, "approved": false, "labels": [], "created_at": "2026-10-02T10:01:44Z", "change_note": "Added tone variable" } ] }

Apps and results

Apps turn approved prompts into forms your team runs in Prompier. When someone shares a result with the team, by hand or from a schedule, your systems can read it here. Private runs, inputs and test runs are never available. Needs a key with the read:results scope (off by default).

Ids are opaque: app_… for apps, res_… for results and run_… for runs you start. Wherever an endpoint takes {app}, pass the app's slug or id. You get result ids from the list calls, from "Copy result ID" in the app, or from the app's link.

List apps

GET /v1/apps

Published apps: id, slug, name, description, output_types. limit and cursor as for prompts.

List team results

GET /v1/apps/{app}/results
GET /v1/apps/{app}/results/latest

Newest first. Use cursor (the response's next_cursor) to page to older ones, and since (the response's latest_cursor, or a timestamp) to get only results shared after that point: poll on a timer. latest returns the newest result in full.

{ "data": [ { "id": "res_91b2c4", "name": "Monday ops actions – 13 Oct 2026", "shared_by": "Marcus Lee", "created_at": "2026-10-13T08:00:00Z", "shared_at": "2026-10-13T08:01:12Z", "app_version": 1 } ], "next_cursor": null, "latest_cursor": "WyIyMDI2LTEwLTEzVDA4OjAwOjAwKzAwOjAwIiwgIi4uLiJd" }

Get a result

GET /v1/results/{id}

Each step says what it holds: output_type (text, document, table, data), format (json, xml, csv for data), media_type, valid, edited and truncated. JSON comes back parsed in data; XML, CSV and text in content; tables as columns and rows.

{ "id": "res_91b2c4", "name": "Monday ops actions – 13 Oct 2026", "steps": [ { "step": 1, "output_type": "data", "format": "json", "media_type": "application/json", "valid": true, "edited": false, "data": { "actions": [ { "action": "Send the Q3 deck", "owner": "Ana" } ] } } ] }

Download the output

GET /v1/results/{id}/output

Just the output, with its real content type and a file name, ready to hand to another system. step is the step number from GET /v1/results/{id} (default: the last one shown); format converts where nothing is lost.

OutputContent-Typeformat=
Data, JSONapplication/jsonnone
Data, XMLapplication/xml; charset=utf-8none
Data, CSVtext/csv; charset=utf-8none
Tabletext/csv; charset=utf-8csv, json, xlsx
Text, Documenttext/markdown; charset=utf-8Document: docx, pdf

CSV cells that start with =, +, - or @ are made safe for spreadsheets. If you need the exact values, read the JSON form (GET /v1/results/{id}), which is always exact.

StatusCodeMeaning
403forbiddenThe key does not have read:results.
404not_foundNo such result in this workspace, or it is no longer shared with the team, was deleted, expired or removed.
406not_acceptableThat format is not available for this output.
422output_invalidThe step's answer was not valid for its format. The raw text is still in GET /v1/results/{id} with valid: false.

Run an app

A script or automation tool can start one of your live apps, wait for it to finish and read what it wrote. Needs a key with the run:apps scope (off by default). Runs spend your team's AI budget: they use the team's AI keys only (never a person's own key), count against the team's spending limits, and show in the team's spend report.

  • The run is started as the person who created the key, who must still be an owner or admin of the team. If they leave, are removed or are no longer an owner or admin, the key is revoked; create a new one.
  • Only an app's published version runs, and only apps without review steps and without a required file field. A run that would cost more than the app's per-run limit is refused.
  • Each key may start 100 runs per day (UTC) by default; an owner or admin can change this on the key. A run can be read only with the key that started it (and by its creator in the app, where it is marked as started through the API). Inputs are never returned.

Start a run

POST /v1/apps/{app}/runs

Body {"inputs": {"field name": "value"}}, using the names of the app's form fields. Send an Idempotency-Key header (up to 200 characters; a new random value per run) so a retry after a timeout never starts a second run: the same key with the same body returns the first run (200 with its current state), the same key with a different body is a 409. The answer is 202 with the run id.

curl -X POST "https://prompier.com/v1/apps/weekly-report/runs" \ -H "Authorization: Bearer $PROMPIER_API_KEY" \ -H "Idempotency-Key: 3f9c1d6e-0b5a-4c1e-9d3a-6f2b7a8e5c10" \ -H "Content-Type: application/json" \ -d '{"inputs": {"topic": "Q3 plan"}}' # 202 { "id": "run_4be07c19a2d3", "status": "queued" }

Get a run

GET /v1/runs/{id}

Poll every few seconds until status is done or error (queued and running are still going). It returns cost in dollars, and once the run has ended its outputs, in the same shape as the steps of GET /v1/results/{id}; steps a conditional app skipped are left out. A failed run has an error with a code and a message, and keeps the outputs of the steps that finished before it. The run id is run_…; if someone shares the run with the team, it also appears under team results with a res_… id.

{ "id": "run_4be07c19a2d3", "status": "done", "cost": 0.0123, "outputs": [ { "step": 1, "name": "Summary", "output_type": "text", "content": "..." } ] }

Download the output

GET /v1/runs/{id}/output

Once the run is done: the same step and format options and file types as the results download. A run that has not finished answers 409 not_finished.

StatusCodeMeaning
403forbidden, testing_disabledThe key lacks run:apps, or your team has not turned on AI runs.
404not_foundNo live app with that slug or id, or no run with that id for this key.
409key_owner_unavailable, needs_review_step, needs_upload, no_team_key, idempotency_conflictThe key's creator can no longer run apps; the app has a review step or needs a file; the team has no AI key for it; or the Idempotency-Key was used for a different request.
422input_missing, input_invalid, input_too_long, over_cost_limitAn input is missing or not valid, or the run would cost more than the app allows.
429daily_limit_reached, too_many_runs_in_progress, rate_limitedThe key's runs for today are used up (wait for Retry-After), the creator has too many calls running, or too many requests.

Team and member spending limits answer 409 team_cap_reached or member_cap_reached when the limit is already used up, and 403 with the same codes when this run's estimated cost would pass it (the member is the key's creator). A team that is locked refuses new runs (402 workspace_locked) but the key can still read its runs.

Errors

We use standard HTTP status codes. Errors return JSON with a machine-readable code and a human-readable message. Every response carries an X-Request-Id header: an 8-character reference that lets support find that exact request.

StatusCodeMeaning
401invalid_api_keyMissing, revoked, expired or mistyped key.
402plan_required, workspace_lockedThe workspace is not on the Team plan, or its trial or subscription has ended.
403forbiddenThe key does not have the scope this endpoint needs.
404not_foundNo prompt with that slug or id, or the version or label is not available to this key.
405method_not_allowedThis endpoint does not accept that method. Prompts and results can only be read; the one thing you can start is an app run.
413output_too_largeThe rendered text is larger than the allowed size.
422missing_variables, invalid_requestA required variable is missing, or a parameter is not valid.
429rate_limitedToo many requests. Wait for Retry-After seconds.
500server_errorSomething went wrong on our side. Safe to retry. The error also carries a ref; quote it when you contact support.
{ "error": { "code": "missing_variables", "message": "Missing values for: topic", "missing": ["topic"] } }

A machine-readable description of the API is available at /v1/openapi.json.

Ready to try it? Create an API key in your team workspace settings, or sign up free and start a team workspace.