# Endpoints

All endpoints require a Bearer token in the `Authorization` header. See [API Overview](https://docs.promptlycms.com/api/overview/) for authentication details.

## GET /prompts/:promptId

Fetch a single prompt by ID.

### Path parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `promptId` | `string` | Yes | The prompt ID from the CMS |

### Query parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `version` | `string` | No | Specific version to fetch (e.g. `1.0.0`). Defaults to latest published version. |

### Example requests

```bash
# Fetch latest version
curl https://api.promptlycms.com/prompts/JPxlUpstuhXB5OwOtKPpj \
  -H "Authorization: Bearer pk_live_..."

# Fetch specific version
curl "https://api.promptlycms.com/prompts/JPxlUpstuhXB5OwOtKPpj?version=2.0.0" \
  -H "Authorization: Bearer pk_live_..."
```
```typescript
// Fetch latest version
const response = await fetch(
  'https://api.promptlycms.com/prompts/JPxlUpstuhXB5OwOtKPpj',
  {
    headers: { Authorization: 'Bearer pk_live_...' },
  },
);
const prompt = await response.json();

// Fetch specific version
const versioned = await fetch(
  'https://api.promptlycms.com/prompts/JPxlUpstuhXB5OwOtKPpj?version=2.0.0',
  {
    headers: { Authorization: 'Bearer pk_live_...' },
  },
);
```
```python
import requests

headers = {"Authorization": "Bearer pk_live_..."}

# Fetch latest version
response = requests.get(
    "https://api.promptlycms.com/prompts/JPxlUpstuhXB5OwOtKPpj",
    headers=headers,
)
prompt = response.json()

# Fetch specific version
response = requests.get(
    "https://api.promptlycms.com/prompts/JPxlUpstuhXB5OwOtKPpj",
    headers=headers,
    params={"version": "2.0.0"},
)
```
### Response

```json
{
  "promptId": "JPxlUpstuhXB5OwOtKPpj",
  "promptName": "Code Review Helper",
  "version": "2.0.0",
  "systemMessage": "You are a helpful code reviewer.",
  "userMessage": "Review this ${language} code:\n${code}",
  "config": {
    "model": "claude-sonnet-4.6",
    "temperature": 0.7,
    "schema": [],
    "inputData": null,
    "inputDataRootName": null
  }
}
```

### Response fields

| Field | Type | Description |
|-------|------|-------------|
| `promptId` | `string` | The prompt ID |
| `promptName` | `string` | Human-readable prompt name |
| `version` | `string` | The resolved version number |
| `systemMessage` | `string` | System message content |
| `userMessage` | `string` | User message template with `${variable}` placeholders |
| `config.model` | `string` | Model identifier from the CMS |
| `config.temperature` | `number` | Temperature setting (0-2) |
| `config.schema` | `SchemaField[]` | Structured output schema fields (empty if none configured) |
| `config.inputData` | `unknown` | Input data configuration |
| `config.inputDataRootName` | `string \| null` | Root name for input data |
| `publishedVersions` | `PublishedVersion[]` | Available published versions (present when `include_versions` is used on list endpoint) |

**Note:** The `userMessage` field contains raw template strings with `${variable}` placeholders. You need to perform string replacement yourself when using the REST API directly. The [SDK](https://docs.promptlycms.com/guides/fetching-prompts/) handles this automatically via the callable `userMessage()` function.

### Full example with the Vercel AI SDK

This example fetches a prompt pinned to a specific version and uses it with `generateText()` from the [Vercel AI SDK](https://ai-sdk.dev/):

```typescript
import { generateText } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';

// Simple helper to replace ${variable} placeholders in template strings
const interpolate = (
  template: string,
  variables: Record<string, string>,
): string => {
  let result = template;
  for (const [key, value] of Object.entries(variables)) {
    result = result.replaceAll(`\${${key}}`, value);
  }
  return result;
};

// 1. Fetch a prompt pinned to a specific version
const response = await fetch(
  `https://api.promptlycms.com/prompts/${promptId}?version=2.27.0`,
  {
    headers: {
      Authorization: `Bearer ${env.PROMPTLY_API_KEY}`,
    },
  },
);

const { userMessage, systemMessage, config } = await response.json();

// 2. Pass the prompt content to the AI SDK
const { text } = await generateText({
  model: anthropic(config.model),
  messages: [
    {
      role: 'system',
      content: systemMessage,
      providerOptions: {
        anthropic: {
          cacheControl: { type: 'ephemeral' },
        },
      },
    },
    {
      role: 'user',
      content: interpolate(userMessage, {
        pickupLocation,
        movesCount: getMovesCount(),
      }),
    },
  ],
  temperature: config.temperature,
});
```

**Tip:** The `interpolate` helper above mirrors what the SDK does internally. If you're using TypeScript, consider using the [SDK](https://docs.promptlycms.com/getting-started/quick-start/) instead - it handles interpolation, model resolution, and type safety automatically.

---

## GET /prompts

Fetch all prompts for your account.

### Query parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `include_versions` | `boolean` | No | Include `publishedVersions` array on each prompt |

### Example requests

```bash
# List all prompts
curl https://api.promptlycms.com/prompts \
  -H "Authorization: Bearer pk_live_..."

# Include version history
curl "https://api.promptlycms.com/prompts?include_versions=true" \
  -H "Authorization: Bearer pk_live_..."
```
```typescript
const response = await fetch('https://api.promptlycms.com/prompts', {
  headers: { Authorization: 'Bearer pk_live_...' },
});
const prompts = await response.json();
```
```python
import requests

response = requests.get(
    "https://api.promptlycms.com/prompts",
    headers={"Authorization": "Bearer pk_live_..."},
)
prompts = response.json()
```
### Response

```json
[
  {
    "promptId": "JPxlUpstuhXB5OwOtKPpj",
    "promptName": "Code Review Helper",
    "version": "2.0.0",
    "systemMessage": "You are a helpful code reviewer.",
    "userMessage": "Review this ${language} code:\n${code}",
    "config": {
      "model": "claude-sonnet-4.6",
      "temperature": 0.7,
      "schema": [],
      "inputData": null,
      "inputDataRootName": null
    }
  }
]
```

### Response with versions

When `include_versions=true`:

```json
[
  {
    "promptId": "JPxlUpstuhXB5OwOtKPpj",
    "promptName": "Code Review Helper",
    "version": "2.0.0",
    "systemMessage": "You are a helpful code reviewer.",
    "userMessage": "Review this ${language} code:\n${code}",
    "config": {
      "model": "claude-sonnet-4.6",
      "temperature": 0.7,
      "schema": [],
      "inputData": null,
      "inputDataRootName": null
    },
    "publishedVersions": [
      { "version": "1.0.0", "userMessage": "Review this code:\n${code}" },
      { "version": "2.0.0", "userMessage": "Review this ${language} code:\n${code}" }
    ]
  }
]
```

---

## GET /composers/:composerId

Fetch a single composer by ID.

### Path parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `composerId` | `string` | Yes | The composer ID from the CMS |

### Query parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `version` | `string` | No | Specific version to fetch (e.g. `1.0.0`). Defaults to latest published version. |

### Example requests

```bash
# Fetch latest version
curl https://api.promptlycms.com/composers/abc123 \
  -H "Authorization: Bearer pk_live_..."

# Fetch specific version
curl "https://api.promptlycms.com/composers/abc123?version=1.0.0" \
  -H "Authorization: Bearer pk_live_..."
```
```typescript
// Fetch latest version
const response = await fetch(
  'https://api.promptlycms.com/composers/abc123',
  {
    headers: { Authorization: 'Bearer pk_live_...' },
  },
);
const composer = await response.json();

// Fetch specific version
const versioned = await fetch(
  'https://api.promptlycms.com/composers/abc123?version=1.0.0',
  {
    headers: { Authorization: 'Bearer pk_live_...' },
  },
);
```
```python
import requests

headers = {"Authorization": "Bearer pk_live_..."}

# Fetch latest version
response = requests.get(
    "https://api.promptlycms.com/composers/abc123",
    headers=headers,
)
composer = response.json()

# Fetch specific version
response = requests.get(
    "https://api.promptlycms.com/composers/abc123",
    headers=headers,
    params={"version": "1.0.0"},
)
```
### Response

```json
{
  "composerId": "abc123",
  "composerName": "My Composer",
  "version": "1.0.0",
  "config": { "schema": [], "inputData": null, "inputDataRootName": null },
  "segments": [
    { "type": "static", "content": "<p>Hello</p>" },
    {
      "type": "prompt",
      "promptId": "p1",
      "promptName": "Intro Prompt",
      "version": "1.0.0",
      "systemMessage": "You are a helpful assistant.",
      "userMessage": "Write an intro for ${text}",
      "config": { "model": "claude-sonnet-4.6", "temperature": 0.7 }
    }
  ]
}
```

### Response fields

| Field | Type | Description |
|-------|------|-------------|
| `composerId` | `string` | The composer ID |
| `composerName` | `string` | Human-readable composer name |
| `version` | `string` | The resolved version number |
| `config.schema` | `SchemaField[]` | Structured output schema fields (empty if none configured) |
| `config.inputData` | `unknown` | Input data configuration |
| `config.inputDataRootName` | `string \| null` | Root name for input data |
| `segments` | `ComposerSegment[]` | Ordered list of static and prompt segments |

Each segment is either a **static segment** with HTML `content`, or a **prompt segment** with `promptId`, `promptName`, `version`, `systemMessage`, `userMessage`, and `config`.

**Note:** The `userMessage` in prompt segments contains raw template strings with `${variable}` placeholders, just like prompts. The [SDK](https://docs.promptlycms.com/reference/client-api/#clientgetcomposercomposerid-options) handles interpolation automatically via the `input` option.

---

## GET /composers

Fetch all composers for your account.

### Query parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `include_versions` | `boolean` | No | Include `publishedVersions` array on each composer |

### Example requests

```bash
# List all composers
curl https://api.promptlycms.com/composers \
  -H "Authorization: Bearer pk_live_..."

# Include version history
curl "https://api.promptlycms.com/composers?include_versions=true" \
  -H "Authorization: Bearer pk_live_..."
```
```typescript
const response = await fetch('https://api.promptlycms.com/composers', {
  headers: { Authorization: 'Bearer pk_live_...' },
});
const composers = await response.json();
```
```python
import requests

response = requests.get(
    "https://api.promptlycms.com/composers",
    headers={"Authorization": "Bearer pk_live_..."},
)
composers = response.json()
```
### Response

```json
[
  {
    "composerId": "abc123",
    "composerName": "My Composer",
    "version": "1.0.0",
    "config": { "schema": [], "inputData": null, "inputDataRootName": null },
    "segments": [
      { "type": "static", "content": "<p>Hello</p>" },
      {
        "type": "prompt",
        "promptId": "p1",
        "promptName": "Intro Prompt",
        "version": "1.0.0",
        "systemMessage": "You are a helpful assistant.",
        "userMessage": "Write an intro for ${text}",
        "config": { "model": "claude-sonnet-4.6", "temperature": 0.7 }
      }
    ]
  }
]
```

### Response with versions

When `include_versions=true`:

```json
[
  {
    "composerId": "abc123",
    "composerName": "My Composer",
    "version": "1.0.0",
    "config": { "schema": [], "inputData": null, "inputDataRootName": null },
    "segments": [
      { "type": "static", "content": "<p>Hello</p>" },
      {
        "type": "prompt",
        "promptId": "p1",
        "promptName": "Intro Prompt",
        "version": "1.0.0",
        "systemMessage": "You are a helpful assistant.",
        "userMessage": "Write an intro for ${text}",
        "config": { "model": "claude-sonnet-4.6", "temperature": 0.7 }
      }
    ],
    "publishedVersions": [
      { "version": "1.0.0" }
    ]
  }
]
```

---

### Error responses

All endpoints return errors in a consistent format. See [Errors](https://docs.promptlycms.com/api/errors/) for the full reference.

```json
{
  "error": "Missing or invalid API key",
  "code": "UNAUTHORIZED"
}
```
```json
{
  "error": "Prompt not found",
  "code": "NOT_FOUND"
}
```
```json
{
  "error": "Usage limit exceeded",
  "code": "USAGE_LIMIT_EXCEEDED",
  "usage": { "used": 5000, "limit": 5000 },
  "upgradeUrl": "https://app.promptlycms.com/settings?upgrade"
}
```