halfoff.devDocs
Obtén una clave
API de modelos

Anthropic Messages

Usa Claude a mitad de precio con tu código actual del SDK de Anthropic. Cambia la URL base; streaming, thinking, uso de funciones, caché y conteo siguen igual.

Si tu código ya habla con Claude mediante el SDK de Anthropic, pasarlo a Half Off Dev son dos ajustes: la URL base https://halfoff.dev y tu clave de Half Off Dev. POST /v1/messages y POST /v1/messages/count_tokens se comportan como Anthropic especifica y el cuerpo de la petición se reenvía sin tocar, así que la referencia de la API de Anthropic sigue siendo tu manual para cada campo. Cada token se cobra a mitad del precio de lista.

Apunta el SDK a Half Off Dev#

El SDK de Anthropic envía la clave en x-api-key; también se acepta como Authorization: Bearer.

curl https://halfoff.dev/v1/messages \
  -H "x-api-key: $HALFOFF_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-5.5",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "Propón tres nombres para un bot que revisa código."}]
  }'

Si tu código crea un cliente por defecto, ni siquiera hay que editarlo: los SDK leen ANTHROPIC_BASE_URL y ANTHROPIC_API_KEY del entorno, así que basta con export ANTHROPIC_BASE_URL=https://halfoff.dev y tu clave.

La gama actual de Claude incluye claude-fable-5.1, claude-opus-5.5, claude-sonnet-5.5 y claude-haiku-5.5, y las versiones anteriores siguen disponibles. La lista de referencia, con precios, está en GET /v1/models.

Recibe los tokens según se generan#

Envía stream: true o usa el helper de streaming del SDK. Los eventos siguen la secuencia de Anthropic: message_start, content_block_start, content_block_delta, content_block_stop, message_delta, message_stop.

with client.messages.stream(
    model="claude-sonnet-5.5",
    max_tokens=2048,
    messages=[{"role": "user", "content": "Redacta una nota de versión breve para una versión de corrección de errores."}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)
    final = stream.get_final_message()
print("\n", final.usage)

Hasta que llega el primer token, el gateway se guarda el stream; si el canal falla en ese intervalo, otro toma el relevo y tú no ves el fallo. Los detalles están en Streaming.

Deja que Claude llame a tus funciones#

Describe cada función con un input_schema en JSON Schema. Una respuesta con stop_reason: "tool_use" te pide que la ejecutes; contesta con un bloque tool_result.

tools = [{
    "name": "convert_currency",
    "description": "Convierte un importe entre dos monedas.",
    "input_schema": {
        "type": "object",
        "properties": {
            "amount": {"type": "number"},
            "from_currency": {"type": "string"},
            "to_currency": {"type": "string"},
        },
        "required": ["amount", "from_currency", "to_currency"],
    },
}]
messages = [{"role": "user", "content": "¿Cuánto son 250 EUR en JPY?"}]

response = client.messages.create(
    model="claude-sonnet-5.5", max_tokens=1024, tools=tools, messages=messages,
)
if response.stop_reason == "tool_use":
    call = next(b for b in response.content if b.type == "tool_use")
    result = {"converted": 40125.0, "currency": call.input["to_currency"]}  # tu código aquí
    messages += [
        {"role": "assistant", "content": response.content},
        {"role": "user", "content": [
            {"type": "tool_result", "tool_use_id": call.id, "content": str(result)},
        ]},
    ]
    response = client.messages.create(
        model="claude-sonnet-5.5", max_tokens=1024, tools=tools, messages=messages,
    )
print(response.content[0].text)

tool_choice, strict y el resto de opciones de Anthropic se reenvían tal cual; la guía de uso de funciones las documenta.

Activa el pensamiento extendido#

Envía thinking y output_config con la forma que Anthropic define para el modelo que llamas. Los modelos recientes piensan de forma adaptativa y reciben un nivel de esfuerzo; Claude 4.5 y anteriores esperan un budget_tokens fijo. Las reglas de cada modelo están en la guía de thinking de Anthropic.

reply = client.messages.create(
    model="claude-opus-5.5",
    max_tokens=16000,
    thinking={"type": "adaptive", "display": "summarized"},
    output_config={"effort": "high"},
    messages=[{"role": "user", "content": "Un tren sale a las 09:40 y llega a las 14:05. ¿Cuántos minutos dura el viaje?"}],
)
for block in reply.content:
    if block.type == "thinking":
        print("Razonamiento:", block.thinking)
    elif block.type == "text":
        print("Resultado:", block.text)

El pensamiento cuenta dentro de usage.output_tokens, así que se cobra a la tarifa de salida (a mitad de precio). Si la conversación continúa tras una llamada a función, devuelve los bloques de thinking exactamente como los recibiste.

Guarda en caché el prefijo que reenvías#

Pon cache_control en el último bloque de la parte que no cambia entre llamadas. La primera llamada escribe la caché; cualquier llamada posterior que empiece con el mismo prefijo la lee por una pequeña fracción de la tarifa de entrada.

response = client.messages.create(
    model="claude-sonnet-5.5",
    max_tokens=1024,
    system=[{
        "type": "text",
        "text": STYLE_GUIDE,
        "cache_control": {"type": "ephemeral"},
    }],
    messages=[{"role": "user", "content": "Reescribe este titular según la guía: 'Ya están los números del T3'"}],
)
u = response.usage
print(u.cache_creation_input_tokens, u.cache_read_input_tokens, u.input_tokens)

Lo que pagas en claude-sonnet-5.5, por millón de tokens: $1.00 por la entrada sin caché, $1.25 por escritura en caché y $0.05 por lectura de caché. Un prefijo por debajo del mínimo del modelo no se guarda, y ambos campos de caché vuelven a cero. El gateway devuelve cada conversación al canal que tiene su caché; en Caché de prompts tienes el panorama completo.

Cuenta los tokens antes de enviar#

POST /v1/messages/count_tokens acepta el cuerpo de un mensaje sin max_tokens y responde con input_tokens. No cuesta nada y funciona aunque tu saldo sea cero.

curl https://halfoff.dev/v1/messages/count_tokens \
  -H "x-api-key: $HALFOFF_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{"model": "claude-sonnet-5.5",
       "messages": [{"role": "user", "content": "¿Cuánto mide este prompt?"}]}'

Una estimación, no la factura

El recuento sirve para comprobar un prompt frente a la ventana de contexto o para presupuestar. Lo que se te cobra sale siempre del bloque usage de la respuesta real del modelo.

Claude Code#

Claude Code usa esta misma API. Exporta ANTHROPIC_BASE_URL=https://halfoff.dev y pon tu clave en ANTHROPIC_AUTH_TOKEN; cada sesión se mantiene en un canal para que su caché siga caliente. La configuración paso a paso, incluidos los ajustes de modelo, está en Claude Code.

Cabeceras de la petición#

CabeceraComportamiento
x-api-key o Authorization: BearerTu clave de Half Off Dev. Obligatoria.
anthropic-versionSe reenvía; 2023-06-01 si la omites.
anthropic-betaSe reenvía sin cambios.
x-halfoff-groupOpcional. Elige el grupo de canales para esta petición, salvo que la clave ya esté vinculada a uno.
x-session-idOpcional. Marca peticiones como una misma conversación para el enrutamiento según caché. metadata.user_id en el cuerpo tiene el mismo efecto.

Las demás cabeceras se descartan. Los errores mantienen la forma de Anthropic, {"type": "error", "error": {"type": "...", "message": "..."}}; los códigos están en Errores.