Hemmingway API platform

API

API docs

How to call Hemmingway-1 from your own code: an OpenAI-compatible endpoint, keys, streaming, thinking, pictures, limits and what it costs. The API is OpenAI-compatible, so most code that already talks to a model needs two lines changed. Keys and billing live on the API platform.

Quick start

The API is OpenAI-compatible. Send requests to https://hemmingway.io/v1 with a key from API keys and the model hemmingway-27b.

curl https://hemmingway.io/v1/chat/completions \
  -H "Authorization: Bearer $HEMMINGWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "hemmingway-27b",
    "messages": [{"role": "user", "content": "Hello"}]
  }'

The Python and JavaScript examples use OpenAI's SDKs: pip install openai or npm install openai.

Authentication

Send the key as a Bearer token in the Authorization header:

Header
Authorization: Bearer hemmingway_live_...
  • Keys start with hemmingway_live_. An account can have 10.
  • A key is shown once, when you make it. Hemmingway keeps only a hash of it.
  • A key spends the credit of the account that made it, or that account's plan — you choose which when you make the key, and it doesn't change. See Keys on your plan.
  • Keep keys out of web pages and apps you hand out.
  • Revoke a key on the API keys page. Requests with it stop working at once.

Models

There is one model, hemmingway-27b. GET /v1/models lists it.

Request
curl https://hemmingway.io/v1/models \
  -H "Authorization: Bearer $HEMMINGWAY_API_KEY"
Response
{"object": "list", "data": [{"id": "hemmingway-27b", "object": "model", "owned_by": "hemmingway"}]}

Chat completions

POST /v1/chat/completions takes the body of OpenAI's Chat Completions. These fields reach the model. Any other field is dropped.

FieldWhat it does
messagesRequired. The conversation in OpenAI's message format, with at least one message. A message's content may be a string, or a list of text and picture parts. See Images.
modelhemmingway-27b. There is one model, and the reply names it hemmingway-27b whatever you send.
max_tokens, max_completion_tokensThe most tokens to write, thinking included. Capped at 32,768, which is also the default.
streamtrue or false. See Streaming.
stream_options{"include_usage": true} adds a last chunk with the token counts.
temperature, top_p, top_k, min_pSampling.
presence_penalty, frequency_penalty, repetition_penaltyPenalties for repeating.
stopText that ends the reply.
seedA number for repeatable sampling.
response_formatOpenAI's response_format, passed to the model.
tools, tool_choice, parallel_tool_callsFunction calling, in OpenAI's format.
reasoning_effort, enable_thinking, chat_template_kwargsThinking. See Thinking.

The reply is OpenAI's chat completion object. usage has the token counts, and the x-request-id header names the request.

Response
{
  "id": "...",
  "object": "chat.completion",
  "model": "hemmingway-27b",
  "choices": [
    {"index": 0, "message": {"role": "assistant", "content": "Hello. What do you need?"}, "finish_reason": "stop"}
  ],
  "usage": {"prompt_tokens": 9, "completion_tokens": 41, "total_tokens": 50}
}

Images

Hemmingway-1 reads pictures. Give a message a list of parts instead of a string: text parts and image_url parts, in the order you want the model to read them. It answers in text.

IMG="data:image/jpeg;base64,$(base64 < photo.jpg | tr -d '\n')"

curl https://hemmingway.io/v1/chat/completions \
  -H "Authorization: Bearer $HEMMINGWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"model\": \"hemmingway-27b\",
    \"messages\": [{\"role\": \"user\", \"content\": [
      {\"type\": \"image_url\", \"image_url\": {\"url\": \"$IMG\"}},
      {\"type\": \"text\", \"text\": \"What is in this picture?\"}
    ]}]
  }"
  • A picture comes as a data: URL, data:image/...;base64,.... A link is turned away with a 400: the model machine would fetch the address itself, so it is never given one.
  • PNG, JPEG, WebP and GIF are read.
  • Up to 4 pictures in one request. A fifth is refused.
  • A picture costs input tokens, about one for every 32×32 pixels: a 512×512 picture is 256 tokens. The most is 1,600 — a picture larger than about 1280×1280 is scaled down to fit — and the least is 64. usage.prompt_tokens_details.multimodal_tokens counts them.
  • Pictures are charged at the input price, like text.
  • A body is at most 4 MB and base64 makes a picture a third larger, so keep the pictures in one request under about 3 MB together.
  • A part that is neither text nor image_url is refused.

Thinking

Hemmingway-1 thinks before it answers, at its highest level unless you ask for less. The thinking comes in reasoning_content, apart from content: on the message, or on each streamed delta.

  • reasoning_effort: low, medium or xhigh, the default. high is read as xhigh and minimal as low. Any other value is refused.
  • enable_thinking: false turns thinking off, at the top level of the body or in chat_template_kwargs.
  • chat_template_kwargs passes only enable_thinking, reasoning_effort and preserve_thinking. Earlier assistant messages sent back with their reasoning_content keep it in the prompt. With preserve_thinking: false, the thinking of those before your last message is left out.
  • Thinking is billed as output tokens and counts toward max_tokens.
# less thinking
curl https://hemmingway.io/v1/chat/completions \
  -H "Authorization: Bearer $HEMMINGWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "hemmingway-27b", "messages": [{"role": "user", "content": "Hello"}], "reasoning_effort": "low"}'

# no thinking
curl https://hemmingway.io/v1/chat/completions \
  -H "Authorization: Bearer $HEMMINGWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "hemmingway-27b", "messages": [{"role": "user", "content": "Hello"}], "enable_thinking": false}'

Streaming

With "stream": true the reply comes as server-sent events: data: lines with chat completion chunks, then data: [DONE].

  • With "stream_options": {"include_usage": true}, a last chunk has usage and no choices.
  • While nothing else comes, a : keep-alive comment line comes every 15 seconds. OpenAI's SDKs skip it.
  • A stream that sends nothing for 5 minutes is cut.
curl -N https://hemmingway.io/v1/chat/completions \
  -H "Authorization: Bearer $HEMMINGWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "hemmingway-27b",
    "messages": [{"role": "user", "content": "Hello"}],
    "stream": true,
    "stream_options": {"include_usage": true}
  }'
Events
data: {"id":"...","object":"chat.completion.chunk","model":"hemmingway-27b","choices":[{"index":0,"delta":{"role":"assistant","content":"Hello"},"finish_reason":null}]}

data: {"id":"...","object":"chat.completion.chunk","model":"hemmingway-27b","choices":[{"index":0,"delta":{"content":". What do you need?"},"finish_reason":"stop"}]}

data: {"id":"...","object":"chat.completion.chunk","model":"hemmingway-27b","choices":[],"usage":{"prompt_tokens":9,"completion_tokens":41,"total_tokens":50}}

data: [DONE]

Errors

An error answers with its HTTP status and a body like this. The message is written for people.

Error
{"error": {"code": "bad_request", "message": "messages must be a list with at least one message."}}
StatusCodeWhen
400bad_requestThe body isn't a JSON object, messages is missing or empty, stream isn't true or false, a picture isn't a data: URL, or the model couldn't take the request.
401bad_keyThe key is unknown or revoked.
401signed_outNo key was sent, or it doesn't start with hemmingway_live_.
402out_of_creditThe account's credit is used up. Add credit on the Billing page.
402no_planThe key draws on a plan, and the account has none any more. Choose a plan, or use a key that draws on credit.
403not_in_apiA key was sent to /v1/tools/. Web search is part of the Hemmingway app.
404not_foundThere is nothing at that address.
413bad_requestThe body is over 4 MB.
429allowanceA key on a plan, and the plan's 5-hour or weekly allowance is used up. resets_at says when it starts again.
429busyThe account already has as many requests running as it may. 8 for a key on credit; the plan's number for a key on a plan.
500server_errorSomething went wrong on Hemmingway's server. The error's rid names the request.
502model_unreachable, model_errorThe model didn't answer, or answered with an error. Try again in a minute.

Limits

  • 8 requests at once per account, across all its keys on credit. A key on a plan uses the plan's number, shared with the app.
  • max_tokens up to 32,768.
  • A request body up to 4 MB.
  • Up to 4 pictures in a request. See Images.
  • A request runs for 13 minutes at most. A stream that sends nothing for 5 minutes is cut.
  • 10 keys per account.
  • The model only. Web search and page reading are part of the Hemmingway app.

Pricing

Prices are in dollars per million tokens.

TokensPrice
Input$0.24
Cached input$0.024
Output, thinking included$0.90
  • A request is charged when it ends, from the token counts the model reports. A reply cut off before its counts is counted at about 4 characters a token.
  • A request the model never got costs nothing.
  • Each request's charge is rounded up to the next millionth of a dollar.
  • Requests are let in while the credit is above zero, so requests running at once can take it a little below zero.

Keys on your plan

On Plus, Pro or Max you can make a key that draws on your plan instead of on credit. It spends the same allowance the Hemmingway app spends, and costs nothing.

  • Choose it when you make the key, on the API keys page. A key can't be changed from one to the other afterwards.
  • Its requests count against your 5-hour and weekly allowance, together with everything you do in the app.
  • When an allowance is used up the key answers 429 allowance, with resets_at. It never falls back to credit.
  • It shares your plan's number of requests at once with the app, and waits in the same place in the queue.
  • It shows on the Usage page with its tokens and requests, at no cost.
  • If the plan ends, the key answers 402 no_plan until you take a plan again.

Cached input

The model machine reuses the start of a prompt it has seen recently: the same system prompt, the same chat so far. Those tokens are charged at the cached input price.

  • There is nothing to switch on. It happens by itself.
  • usage.prompt_tokens_details.cached_tokens says how many of the prompt_tokens were cached. The rest are charged as input.
  • A reply can come without cached_tokens. Then the whole prompt was charged as input.
  • Only the start of a prompt can be reused. Keep what stays the same first and what changes last.
Usage
"usage": {
  "prompt_tokens": 1200,
  "completion_tokens": 41,
  "total_tokens": 1241,
  "prompt_tokens_details": {"cached_tokens": 1104}
}

Credit

  • A key on credit is paid from prepaid credit. Add it on the Billing page: $5, $20, $50, $100 or any amount from $5. Prices include tax.
  • Credit lasts 12 months from when you buy it. The oldest credit is used first, and what is left of a purchase after 12 months expires.
  • Credit isn't refunded, except where the law requires it. See the Terms.