PerslyPersly API
API Reference

Chat Completions

Generate medical AI chat responses with source citations.

POST https://api.persly.ai/v1/chat/completions

Creates a chat completion for the given messages. Returns a medical AI response with optional source citations, follow-up question suggestions, and streaming support.

Request Body

ParameterTypeRequiredDefaultDescription
modelstringYesModel ID. Either persly-chat-v1 or persly-chat-pro-v1
messagesarrayYesArray of input messages. Must be non-empty and at most 200 items.
messages[].rolestringYesRole of the message author: user or assistant
messages[].textstringYesMessage text content. Max 32,000 characters.
messages[].image_urlsstring[]No[]List of image URLs (JPG, PNG, WEBP). Public URLs or data URLs.
messages[].pdf_urlsstring[]No[]List of PDF URLs. Public URLs or data URLs.
streambooleanNofalseIf true, response is streamed as Server-Sent Events
include_follow_upsbooleanNofalseInclude follow-up question suggestions
include_domainsstring[] | nullNonullApply best-effort domain filtering during retrieval. Use Domains to discover common values.
exclude_domainsstring[] | nullNonullApply best-effort exclusion filtering during retrieval. Use Domains to discover common values.
instructionsstring | nullNonullSystem-level instructions for answer generation. Max 4,000 characters.
languagestring | nullNonullOutput language hint (free-form string). Max 64 characters.

Request constraints:

  • messages can include up to 200 items.
  • Supported attachment formats: JPG/JPEG, PNG, WEBP, PDF.
  • Attachment limits: persly-chat-v1 up to 30 pages, persly-chat-pro-v1 up to 60 pages.

  • Counting rule: 1 image = 1 page, 1 PDF page = 1 page.
  • Total attachment payload per request must be 40 MB or less.
  • Each messages[].text value must be at most 32,000 characters.

Requesting include_follow_ups does not guarantee follow-up questions. The follow-up surcharge is applied only when follow-up generation is actually invoked.

Chat pricing is additive:

  • Base request: persly-chat-v1 = $0.15, persly-chat-pro-v1 = $0.50

  • Follow-up generation surcharge: +$0.01 (only when invoked)
  • Attachment surcharge:

    • persly-chat-v1: +$0.003 per page (images/PDF), up to 30 pages

    • persly-chat-pro-v1: +$0.01 per page (images/PDF), up to 60 pages

For persly-chat-pro-v1, if language is omitted, the internal default is auto.

include_domains and exclude_domains are mutually exclusive. Sending both as non-empty arrays returns 422 validation error.

Response Body (Non-streaming)

FieldTypeDescription
stepsarrayAI processing steps
steps[].descriptionstringStep description (e.g. "Searching medical knowledge base")
steps[].actionsarrayActions performed during this step
steps[].actions[].typestringAction type (e.g. search_official_source)
steps[].actions[].inputobjectAction input parameters
steps[].actions[].resultarrayAction results
messagestringThe AI-generated response text
sourcesarray | nullMedical source citations. null when no citations are returned.
sources[].titlestringSource document title
sources[].urlstringSource URL
sources[].relevance_scorenumberRelative relevance score as a float (higher means more relevant; do not assume a fixed 0.0–1.0 range)
follow_up_questionsarray | nullSuggested follow-up questions. null when include_follow_ups: false or none are generated.

For stream: true, see the Streaming guide for the SSE protocol.

Examples

Basic Request

curl https://api.persly.ai/v1/chat/completions \
  -H "Authorization: Bearer $PERSLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "persly-chat-v1",
    "messages": [
      {"role": "user", "text": "What are the first-line treatments for type 2 diabetes?"}
    ]
  }'
import requests

response = requests.post(
    "https://api.persly.ai/v1/chat/completions",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={
        "model": "persly-chat-v1",
        "messages": [
            {
                "role": "user",
                "text": "What are the first-line treatments for type 2 diabetes?",
            }
        ],
    },
)

data = response.json()
print(data["message"])

for source in (data.get("sources") or []):
    print(f"  Source: {source['title']} ({source['url']})")
const response = await fetch("https://api.persly.ai/v1/chat/completions", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "persly-chat-v1",
    messages: [
      { role: "user", text: "What are the first-line treatments for type 2 diabetes?" },
    ],
  }),
});

const data = await response.json();
console.log(data.message);

for (const source of data.sources ?? []) {
  console.log(`  Source: ${source.title} (${source.url})`);
}

Response

{
  "steps": [
    {
      "description": "Searching medical knowledge base",
      "actions": [
        {
          "type": "search_official_source",
          "input": { "query": "type 2 diabetes first-line treatment" },
          "result": [
            {
              "title": "ADA Standards of Medical Care in Diabetes",
              "url": "https://diabetesjournals.org/care/...",
              "content": "Metformin remains the preferred initial pharmacologic agent..."
            }
          ]
        }
      ]
    }
  ],
  "message": "The first-line treatment for type 2 diabetes is metformin, along with lifestyle modifications including diet and exercise. According to the ADA Standards of Care, metformin remains the preferred initial pharmacologic agent due to its efficacy, safety profile, and low cost...",
  "sources": [
    {
      "title": "ADA Standards of Medical Care in Diabetes",
      "url": "https://diabetesjournals.org/care/article/47/Supplement_1/S1/...",
      "relevance_score": 0.97
    },
    {
      "title": "Metformin - StatPearls",
      "url": "https://www.ncbi.nlm.nih.gov/books/NBK518983/",
      "relevance_score": 0.92
    }
  ],
  "follow_up_questions": null
}

With Follow-up Questions

curl https://api.persly.ai/v1/chat/completions \
  -H "Authorization: Bearer $PERSLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "persly-chat-v1",
    "messages": [{"role": "user", "text": "What is hypertension?"}],
    "include_follow_ups": true
  }'
Response with follow-up questions
{
  "steps": [
    {
      "description": "Searching medical knowledge base",
      "actions": [
        {
          "type": "search_official_source",
          "input": { "query": "hypertension" },
          "result": [
            {
              "title": "Hypertension - StatPearls",
              "url": "https://www.ncbi.nlm.nih.gov/books/NBK539859/",
              "content": "Hypertension is defined as..."
            }
          ]
        }
      ]
    }
  ],
  "message": "Hypertension, or high blood pressure, is a condition...",
  "sources": [
    {
      "title": "Hypertension - StatPearls",
      "url": "https://www.ncbi.nlm.nih.gov/books/NBK539859/",
      "relevance_score": 0.95
    }
  ],
  "follow_up_questions": [
    "What are the risk factors for hypertension?",
    "How is hypertension diagnosed?",
    "What lifestyle changes can help manage hypertension?"
  ]
}

With Image or PDF Input

curl https://api.persly.ai/v1/chat/completions \
  -H "Authorization: Bearer $PERSLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "persly-chat-v1",
    "messages": [
      {
        "role": "user",
        "text": "Please review these files.",
        "image_urls": ["https://example.com/lab-chart.png"],
        "pdf_urls": ["https://example.com/lab-report.pdf"]
      }
    ]
  }'

Cost example: A persly-chat-v1 request with 2 images and a 3-page PDF counts as 5 pages. Total cost is $0.15 + (5 × $0.003) = $0.165, plus +$0.01 only when follow-up generation is invoked.

With Instructions and Language Hint

curl https://api.persly.ai/v1/chat/completions \
  -H "Authorization: Bearer $PERSLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "persly-chat-v1",
    "messages": [{"role": "user", "text": "Explain hypertension in simple terms."}],
    "instructions": "Use a concise clinical tone and avoid bullet points.",
    "language": "arabic"
  }'

With Domain Filter

Use Domains to fetch common values before sending filters. Domain tokens are normalized, invalid/non-normalized values can be ignored, and filtering is best-effort so off-domain results may still appear.

curl https://api.persly.ai/v1/chat/completions \
  -H "Authorization: Bearer $PERSLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "persly-chat-v1",
    "messages": [{"role": "user", "text": "Summarize hypertension treatment."}],
    "include_domains": ["nih.gov", "who.int"]
  }'
Exclude specific domains
curl https://api.persly.ai/v1/chat/completions \
  -H "Authorization: Bearer $PERSLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "persly-chat-v1",
    "messages": [{"role": "user", "text": "Summarize hypertension treatment."}],
    "exclude_domains": ["wikipedia.org"]
  }'

Streaming

See the Streaming guide for detailed SSE protocol documentation.

curl https://api.persly.ai/v1/chat/completions \
  -H "Authorization: Bearer $PERSLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "persly-chat-v1",
    "messages": [{"role": "user", "text": "Explain the pathophysiology of asthma."}],
    "stream": true
  }'

Errors

StatusCodeCause
400model_not_foundInvalid model name
400missing_required_fieldEmpty messages array
400invalid_requestInvalid role or empty messages
400too_many_messagesmessages array exceeds 200 items
400content_too_longAny messages[].text exceeds 32,000 characters
422Request validation error (missing required fields, wrong type, or both domain filters provided as non-empty arrays)
401authentication_errorMissing or invalid Authorization header, or invalid API key (including malformed, unknown, or revoked keys).
402insufficient_creditsCredit balance too low
500internal_errorUnexpected server-side failure for non-streaming/pre-stream requests (streaming failures surface as in-band SSE error events with the same code)

On this page