Quick Snippet — Invoke a Prompt with One Variable

This snippet shows the minimal, production-ready code to call a managed prompt from your client or backend, passing one dynamic variable through.

Assume the prompt welcome-email is already defined in your odnoga prompt registry with the template:

Hello {{user_name}},

Welcome to our platform!

Node.js (OpenAI SDK)

import OpenAI from 'openai';

async function sendWelcomeEmail(userName: string, userId: string) {
  const client = new OpenAI({
    apiKey: process.env.AIROUTER_API_KEY,
    baseURL: process.env.AIROUTER_BASE_URL,
  });

  const response = await client.chat.completions.create({
    model: 'gpt-4o-mini',
    prompt: {
      slug: 'welcome-email',
      label: 'production',
      variables: {
        user_name: userName,
      },
    },
    max_tokens: 1024,
  }, {
    headers: {
      'x-airouter-end-user': userId,
    },
  });

  return {
    message: response.choices[0].message.content,
    cost: response.headers['x-airouter-cost-usd'],
    requestId: response.headers['x-airouter-request-id'],
  };
}

// Usage
const result = await sendWelcomeEmail('Alice', 'user_12345');
console.log(result.message);

Python (OpenAI SDK)

import os
from openai import OpenAI

def send_welcome_email(user_name: str, user_id: str):
    client = OpenAI(
        api_key=os.getenv('AIROUTER_API_KEY'),
        base_url=os.getenv('AIROUTER_BASE_URL'),
    )

    response = client.chat.completions.create(
        model='gpt-4o-mini',
        prompt={
            'slug': 'welcome-email',
            'label': 'production',
            'variables': {
                'user_name': user_name,
            },
        },
        max_tokens=1024,
        headers={
            'x-airouter-end-user': user_id,
        },
    )

    return {
        'message': response.choices[0].message.content,
        'cost': response.headers['x-airouter-cost-usd'],
        'request_id': response.headers['x-airouter-request-id'],
    }

# Usage
result = send_welcome_email('Alice', 'user_12345')
print(result['message'])

cURL (Direct HTTP)

#!/bin/bash

USER_NAME="Alice"
USER_ID="user_12345"

curl -X POST \
  "$AIROUTER_BASE_URL/v1/chat/completions" \
  -H "authorization: Bearer $AIROUTER_API_KEY" \
  -H "content-type: application/json" \
  -H "x-airouter-end-user: $USER_ID" \
  -d '{
    "model": "gpt-4o-mini",
    "prompt": {
      "slug": "welcome-email",
      "label": "production",
      "variables": {
        "user_name": "'$USER_NAME'"
      }
    },
    "max_tokens": 1024
  }' | jq '.choices[0].message.content'

JavaScript (Fetch API, for Node/Edge)

async function sendWelcomeEmail(userName, userId) {
  const response = await fetch(
    `${process.env.AIROUTER_BASE_URL}/v1/chat/completions`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.AIROUTER_API_KEY}`,
        'Content-Type': 'application/json',
        'x-airouter-end-user': userId,
      },
      body: JSON.stringify({
        model: 'gpt-4o-mini',
        prompt: {
          slug: 'welcome-email',
          label: 'production',
          variables: {
            user_name: userName,
          },
        },
        max_tokens: 1024,
      }),
    }
  );

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error.message);
  }

  const data = await response.json();

  return {
    message: data.choices[0].message.content,
    cost: response.headers.get('x-airouter-cost-usd'),
    requestId: response.headers.get('x-airouter-request-id'),
  };
}

// Usage
const result = await sendWelcomeEmail('Alice', 'user_12345');
console.log(result.message);

Go

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
)

type PromptRequest struct {
	Model  string `json:"model"`
	Prompt struct {
		Slug      string            `json:"slug"`
		Label     string            `json:"label"`
		Variables map[string]string `json:"variables"`
	} `json:"prompt"`
	MaxTokens int `json:"max_tokens"`
}

type Choice struct {
	Message struct {
		Content string `json:"content"`
	} `json:"message"`
}

type CompletionResponse struct {
	Choices []Choice `json:"choices"`
}

func SendWelcomeEmail(userName, userId string) (string, error) {
	payload := PromptRequest{
		Model: "gpt-4o-mini",
		MaxTokens: 1024,
	}
	payload.Prompt.Slug = "welcome-email"
	payload.Prompt.Label = "production"
	payload.Prompt.Variables = map[string]string{
		"user_name": userName,
	}

	body, _ := json.Marshal(payload)

	req, _ := http.NewRequest(
		"POST",
		os.Getenv("AIROUTER_BASE_URL")+"/v1/chat/completions",
		bytes.NewBuffer(body),
	)

	req.Header.Set("Authorization", "Bearer "+os.Getenv("AIROUTER_API_KEY"))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("x-airouter-end-user", userId)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	respBody, _ := io.ReadAll(resp.Body)
	var result CompletionResponse
	json.Unmarshal(respBody, &result)

	return result.Choices[0].Message.Content, nil
}

func main() {
	message, _ := SendWelcomeEmail("Alice", "user_12345")
	fmt.Println(message)
}

Key Points

Prompt slug — Must match exactly (case-sensitive).
Label — Typically "production" for live prompts; use "staging" for drafts.
Variables — A map/dict with key names matching {{placeholders}} in your prompt template.
End-user header — Always set x-airouter-end-user for accurate usage attribution.
Error handling — Check HTTP status; 400 means invalid variable, 404 means prompt not found.


Response Headers

Every successful response includes:

x-airouter-request-id: 8b1a…          # Unique request ID
x-airouter-cost-usd: 0.000043         # Cost of this request
x-airouter-latency-ms: 612            # Upstream latency
x-airouter-cache: miss|hit|off        # Cache status
x-ratelimit-remaining-usd: 49.9999    # Budget remaining

Log these for observability and cost tracking.


Errors

StatusCodeReason
400invalid_promptRequired variable missing
400variable_too_largeVariable over its cap (8 KB default; the prompt's declaration can raise it with max_bytes, up to 256 KB)
404prompt_not_foundSlug doesn't exist in your workspace
402budget_exhaustedBudget limit reached

See Also