Paper Instruments
Ultramarine API

Messages

Use the Anthropic SDK, Claude Agent SDK, and Claude Code with Ultramarine.

POST https://api.paperinstruments.com/v1/messages
x-api-key: $PAPERINSTRUMENTS_API_KEY
anthropic-version: 2023-06-01
Content-Type: application/json

The endpoint accepts the Anthropic Messages format with the parameters listed below. Authenticate with x-api-key or Authorization: Bearer. If you send both, they must match.

Anthropic SDK

Set the base URL to https://api.paperinstruments.com.

import os
import anthropic

client = anthropic.Anthropic(
    base_url="https://api.paperinstruments.com",
    api_key=os.environ["PAPERINSTRUMENTS_API_KEY"],
)

with client.messages.stream(
    model="ultramarine-1-flash",
    max_tokens=8192,
    messages=[{"role": "user", "content": "Explain EBITDA."}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

Claude Agent SDK and Claude Code

Set these environment variables:

VariableValue
ANTHROPIC_BASE_URLhttps://api.paperinstruments.com
ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKENYour API key
ANTHROPIC_MODEL, ANTHROPIC_DEFAULT_OPUS_MODEL, ANTHROPIC_DEFAULT_SONNET_MODEL, ANTHROPIC_DEFAULT_HAIKU_MODEL, CLAUDE_CODE_SUBAGENT_MODELultramarine-1-flash
CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS1

These settings return 400:

SettingUse instead
CLAUDE_CODE_EFFORT_LEVEL=medium or xhighlow, high, or max
MAX_THINKING_TOKENSLeave unset
CLAUDE_CODE_MAX_OUTPUT_TOKENS above 3276832768 or less
Tool searchENABLE_TOOL_SEARCH=false
A one-hour prompt-cache TTLThe default cache setting

Any model name other than ultramarine-1-flash returns 404.

In Claude Code, WebSearch does not work and reading a PDF returns an error.

import asyncio
import os
from claude_agent_sdk import ClaudeAgentOptions, query

ENV = {
    "ANTHROPIC_BASE_URL": "https://api.paperinstruments.com",
    "ANTHROPIC_API_KEY": os.environ["PAPERINSTRUMENTS_API_KEY"],
    "ANTHROPIC_MODEL": "ultramarine-1-flash",
    "ANTHROPIC_DEFAULT_OPUS_MODEL": "ultramarine-1-flash",
    "ANTHROPIC_DEFAULT_SONNET_MODEL": "ultramarine-1-flash",
    "ANTHROPIC_DEFAULT_HAIKU_MODEL": "ultramarine-1-flash",
    "CLAUDE_CODE_SUBAGENT_MODEL": "ultramarine-1-flash",
    "CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS": "1",
}


async def main():
    options = ClaudeAgentOptions(
        model="ultramarine-1-flash", env=ENV, allowed_tools=["Read", "Grep"]
    )
    async for message in query(prompt="Summarize README.md.", options=options):
        print(message)


asyncio.run(main())

For the Claude Code CLI, export the same variables and run claude --model ultramarine-1-flash.

Parameters

ParameterAccepted values
modelRequired. ultramarine-1-flash
max_tokensRequired. 1 to 32,768
messagesRequired. user and assistant turns, ending with a user turn
systemString or text blocks
output_config.effortlow, high, or max. Default: max, which we recommend for best results.
output_config.format{"type": "json_schema", "schema": {...}}
thinking{"type": "adaptive"}, optionally with "display": "omitted"
streamtrue or false
toolsCustom tools with name, description, input_schema, and optional strict
tool_choiceauto, any, none, or {"type": "tool", "name": "..."}, with optional disable_parallel_tool_use
temperature0 to 1
top_p0 to 1
top_kInteger, 0 or more
metadata.user_idString, up to 512 characters
cache_control{"type": "ephemeral"}
context_management{"edits": [{"type": "clear_thinking_20251015", "keep": "all"}]}

Tool names use 1 to 64 letters, digits, _, or -. Request bodies can be up to 20 MiB.

Content

BlockWhere
textAny turn
image with a base64 source (PNG, JPEG, GIF, WebP) or a public url sourceUser turns and tool_result
tool_useAssistant turns
tool_result with a string, text blocks, or images, and optional is_errorThe user turn after the tool_use

A request can include up to 16 images. Each image can be up to 10 MiB and 32 million pixels, and cannot be animated.

Return one tool_result for each tool_use, before any other content in that user turn.

To add a system message mid-conversation, send anthropic-beta: mid-conversation-system-2026-04-07 and include a {"role": "system"} text turn after a user turn.

Headers

HeaderAccepted values
anthropic-version2023-06-01
x-session-idOptional. A stable conversation ID you can use for sticky routing. Reuse the same value across requests in a conversation.
anthropic-betaclaude-code-20250219, mid-conversation-system-2026-04-07, effort-2025-11-24, interleaved-thinking-2025-05-14, context-management-2025-06-27

Conversation caching

The x-session-id header is optional. You can use it if you want sticky routing. When using it, reuse the same value for every turn, retry, and tool result in a conversation, and use a different value for each conversation.

Pass extra_headers={"x-session-id": "your-conversation-id"} in the Python Anthropic SDK, or { headers: { "x-session-id": "your-conversation-id" } } as the second argument to messages.create or messages.stream in Node.js.

Keep repeated prompt prefixes stable. Cache hits depend on matching prefixes and cache availability. Send the full message history on each request.

Not supported

Stop sequences (stop_sequences) are not currently supported.

These return 400 invalid_request_error. The error message names the field.

FeatureField
Disabled thinking and thinking budgetsthinking
Summarized thinkingthinking.display
thinking and redacted_thinking blocks in historymessages
Effort other than low, high, or maxoutput_config.effort
PDFs and other documentsdocument blocks
Search resultssearch_result blocks
Files API sourcessource.type: "file"
Citationscitations
Cache TTLs and cache types other than ephemeralcache_control
Server tools: web search, web fetch, code execution, MCP connector, tool searchtools[].type
Deferred tools, programmatic tool calling, toolsetsdefer_loading, caller, toolset_name
Other context edits and compactioncontext_management, compaction
Turn-scoped system messages and per-message effortclear_at, output_config on a message
Safeguardssafeguards
Assistant prefillA final assistant turn
Images in assistant or system turnsimage blocks
Other beta headersanthropic-beta
Other API versionsanthropic-version
Any other field, such as service_tier or inference_geoThe field name

Token counting, Message Batches, the Files API, and the Models API are not available.

Errors

Errors use the Anthropic error format and include a request_id:

{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "thinking.type: Disabling thinking is not supported."
  },
  "request_id": "req_..."
}
StatusTypeWhen
400invalid_request_errorInvalid or unsupported request
401authentication_errorMissing or invalid API key
404not_found_errorUnknown model
429rate_limit_errorRate limit reached or insufficient balance
502api_errorInvalid model output
503api_errorNo capacity. Retry with backoff

See Errors for retries.

On this page