M01-L05 · source screen S05 · 12 min

The technical substrate: SDKs, REST, streaming, async

0:00 / 0:00

Learning objectives

  • Explain that Claude is reached over an HTTP REST API, and what an official SDK adds.
  • Choose between synchronous and streaming responses based on whether a user is watching.
  • Distinguish async/await concurrency from the Message Batches API, and pick the right one for high-volume work.

Estimated teaching time: 12 min · Prerequisites: M01-L02 (tokens); Basic familiarity with HTTP requests helps

1. How a developer reaches Claude: SDK versus raw REST

REST API
In plain English: A web interface you call with ordinary HTTP requests. You send a request to a URL (an endpoint) and get a response back, here with JSON in both directions.
Analogy: Like sending a form by post and getting a typed letter back: the envelope (HTTP) and form layout (JSON) are standard.

At its core, Claude is reached over an HTTP REST API: your code sends a request to an endpoint with your API key and a JSON body, and reads a JSON response back. You can call that endpoint directly with any HTTP client.

Calling the REST endpoint directlySyntax-checked, not run against the API
curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-5-5",
    "max_tokens": 300,
    "messages": [{"role": "user", "content": "Where is my order #A1042?"}]
  }'
Shell syntax checked with bash -n. Endpoint and headers per the Messages API reference. Not sent (no API key in the build environment).
SDK (software development kit)
In plain English: An official library, available for Python and TypeScript among others, that wraps the same REST API so you write less boilerplate.
Why it matters: It handles authentication, request construction, retries, and response parsing for you.

The SDK and raw REST reach the same API and the same model. The SDK just saves you from assembling requests by hand. Module 2 builds against the SDK and the Messages API, which sits on this same foundation.

2. Synchronous, streaming, and real-time responses

PatternHow it behavesUse it when
SynchronousSend the request, wait for the complete response in one piece, then act on it.Short responses and backend jobs where no one is waiting.
StreamingThe response arrives in pieces as the model generates it; your code reassembles the final message.Long responses, or a user is watching: output appears immediately instead of after a blank-screen wait.

Claude exposes streaming over the same HTTP connection using server-sent events (SSE): a standard way for a server to push a sequence of small, named events down one open HTTP response.

Streaming a reply to a waiting userSyntax-checked, not run against the API
import anthropic

client = anthropic.Anthropic()

with client.messages.stream(
    model="claude-sonnet-5-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Explain our return policy step by step."}],
) as stream:
    for text in stream.text_stream:       # pieces arrive as they are generated
        print(text, end="", flush=True)   # show them to the user immediately
    message = stream.get_final_message()  # the reassembled, complete Message

print("\nstop reason:", message.stop_reason)
Compiled with python -m py_compile; messages.stream, text_stream and get_final_message per the streaming docs and anthropic 1.15.0. Not executed against the API.

3. Asynchronous patterns for high-volume work

Two patterns address high-volume work, and they solve different problems.

AsyncAnthropic
In plain English: The async client exposed by the Python SDK. Uses non-blocking async/await to make API calls without tying up your application thread while the request returns in real time.
Why it matters: Source glossary definition. In the TypeScript SDK the standard Anthropic client is Promise-based, so you await calls directly; there is no separate async class.
Concurrency without blocking (AsyncAnthropic)Syntax-checked, not run against the API
import asyncio

import anthropic

client = anthropic.AsyncAnthropic()
limit = asyncio.Semaphore(5)  # stay well inside your rate limits


async def summarize(ticket: str) -> str:
    async with limit:
        response = await client.messages.create(
            model="claude-haiku-5-5",
            max_tokens=200,
            messages=[{"role": "user", "content": f"Summarize in one line: {ticket}"}],
        )
    return next(b.text for b in response.content if b.type == "text")


async def main(tickets: list[str]) -> list[str]:
    # Many requests in flight at once; each still returns in real time.
    return await asyncio.gather(*(summarize(t) for t in tickets))


if __name__ == "__main__":
    print(asyncio.run(main(["Parcel late", "Wrong size", "Double charge"])))
Compiled with python -m py_compile; AsyncAnthropic confirmed in anthropic 1.15.0. Reads the first text block, since current models may return a thinking block first. Not executed against the API.
Message Batches API
In plain English: A separate pattern for bulk offline workloads: submit a large set of requests in one call, receive an identifier, and poll for completion. Can take up to 24 hours and runs at a lower per-token cost.
Why it matters: Source glossary definition. It suits offline pipelines, evaluation runs, and bulk jobs where no user is waiting and cost matters more than turnaround time.
A bulk offline job with the Message Batches APISyntax-checked, not run against the API
import time

import anthropic

client = anthropic.Anthropic()
reviews = {"r-001": "Great boots, fast delivery.", "r-002": "Zip broke in a week."}

batch = client.messages.batches.create(
    requests=[
        {
            "custom_id": review_id,
            "params": {
                "model": "claude-haiku-5-5",
                "max_tokens": 50,
                "messages": [{"role": "user", "content": f"Sentiment of: {text}"}],
            },
        }
        for review_id, text in reviews.items()
    ]
)
print("submitted", batch.id)  # keep this identifier

while client.messages.batches.retrieve(batch.id).processing_status != "ended":
    time.sleep(60)  # nobody is waiting; poll slowly

for result in client.messages.batches.results(batch.id):
    if result.result.type == "succeeded":
        text = next(b.text for b in result.result.message.content if b.type == "text")
        print(result.custom_id, text)
    else:
        print(result.custom_id, result.result.type)  # errored / canceled / expired
Compiled with python -m py_compile; batches.create/retrieve/results, processing_status and result.result.type/message confirmed against anthropic 1.15.0 types on 2026-10-20. Not executed against the API.
SituationPattern
A short answer for a backend jobSynchronous
A customer is watching a long answer appearStreaming
Your web server handles many requests at once and must not blockAsync/await client
50,000 product reviews to classify overnight, nobody waitingMessage Batches API

References

  • Streaming messages (Claude Platform Docs) · checked 2026-10-20
    Server-sent events; event order message_start → content blocks (start/delta/stop) → message_delta → message_stop; ping and error events; messages.stream and get_final_message.
  • Batch processing (Claude Platform Docs) · checked 2026-10-20
    50% of standard prices; up to 100,000 requests or 256 MB per batch; most finish within 1 hour, results when all done or after 24 hours; processing_status in_progress → ended; result types succeeded / errored / canceled / expired; results kept 29 days.
  • Messages API reference · checked 2026-10-20
    Endpoint POST /v1/messages; x-api-key and anthropic-version headers.
  • anthropic Python SDK 1.15.0 (installed locally) · checked 2026-10-20
    Confirmed AsyncAnthropic, messages.stream, messages.batches.create/retrieve/results, MessageBatch.processing_status, result.result.type/message.

Source notes

  • Primary source: S05 of 'MSO Foundations: Developer Module 1', three tab panels plus two glossary tooltips (AsyncAnthropic, Message Batches API).
  • Supplementary from docs (labelled in the lesson): the exact SSE event order, the 50% batch discount, batch size limits, typical completion within 1 hour, result types and retention. The source says only 'lower per-token cost' and 'up to 24 hours'.
  • The TypeScript statement (Promise-based client, no separate async class) is source content; it was not re-verified against the TypeScript SDK in this build.