{"course":{"slug":"choosing-your-tools","title":"Choosing and Using the Tools","url":"https://addaly.com/learn/choosing-your-tools","level":"beginner","track":"work"},"lesson":{"slug":"first-api-call","title":"Your first API call","url":"https://addaly.com/learn/choosing-your-tools/first-api-call","position":21,"of":76,"minutes":9,"answer":"An API request is a model name, a list of role-tagged messages and a few settings, and because most providers accept the same format.","keyIdea":"An API request is a model name, a list of role-tagged messages and a few settings, and because most providers accept the same format, moving between vendors or to a local model is usually a change of two lines."},"body":{"format":"markdown","text":"## Why this is worth thirty minutes even if you are not a programmer\n\nThe API is the route where you pay for what you use rather than a flat monthly fee, where you can pin a model version, where you choose the system prompt, and where nothing about the product layer is decided for you. For a light user it is often a tenth of the subscription price. For anyone processing more than a handful of items it is the only sensible route.\n\nYou do not need to write software to use it. Free chat front-ends, covered two lessons from now, take a key and give you a chat window. But it helps enormously to see what one request looks like, because then the whole architecture stops being mysterious.\n\n## The request\n\nEvery major provider accepts something close to this shape. Sign up, create a key in the console, then:\n\n```bash\ncurl https://api.openai.com/v1/chat/completions \\\n  -H \"Authorization: Bearer $OPENAI_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"model\": \"gpt-4o-mini\",\n    \"messages\": [\n      {\"role\": \"system\", \"content\": \"You are terse. British spelling.\"},\n      {\"role\": \"user\",   \"content\": \"Three risks of a fixed-price contract.\"}\n    ],\n    \"temperature\": 0.3\n  }'\n```\n\nThat is the whole thing. A model name, a list of messages with roles, and a couple of settings. In Python:\n\n```python\nfrom openai import OpenAI\nclient = OpenAI()                      # reads OPENAI_API_KEY from the environment\nr = client.chat.completions.create(\n        model=\"gpt-4o-mini\",\n        messages=[{\"role\": \"user\", \"content\": \"Summarise this in 40 words: ...\"}])\nprint(r.choices[0].message.content)\nprint(r.usage)                         # prompt_tokens, completion_tokens\n```\n\nTwo things in there matter more than they look. The **system** role is the layer that consumer products fill in for you and you now control. And `r.usage` prints exactly what you were charged for, which makes cost concrete rather than theoretical from the first minute.\n\n## The convention that makes models interchangeable\n\nThat request format started at OpenAI and became a de facto standard. Most providers and nearly every local runner now accept it, which means switching models is often a change of two lines:\n\n```python\nclient = OpenAI(base_url=\"https://api.anthropic.com/v1/\",  api_key=A_KEY)\nclient = OpenAI(base_url=\"https://openrouter.ai/api/v1\",   api_key=R_KEY)\nclient = OpenAI(base_url=\"http://localhost:11434/v1\",      api_key=\"ollama\")\n```\n\nThe last line is a model running on your own laptop, answering the same code. This compatibility is the single most valuable thing about the API route, because it makes your work portable in a field where products are withdrawn regularly.\n\nCompatibility is not perfect. Vendor-specific features (thinking budgets, caching controls, certain tool formats) usually need that vendor's own library. The common path works everywhere; the interesting features do not.\n\n## Reading the response\n\nThe reply comes back as JSON, and three fields in it are worth knowing by name. `choices[0].message.content` is the answer. `usage` is the token counts you were billed for. And `finish_reason` tells you *why* the model stopped: `stop` means it finished naturally, `length` means it hit the maximum output you allowed and was cut off mid-sentence.\n\nThat last one explains a complaint people bring to support constantly: answers that end halfway through a word. It is almost never the model failing; it is a `max_tokens` setting somewhere, either yours or the front-end's default. Raise it, or ask for a shorter answer, and the truncation goes away.\n\n## What it does not give you\n\nBe clear about what you are giving up, because people are sold the API as strictly better and it is not.\n\n- **No memory.** Every request is independent. A conversation exists only because you resend the previous messages, and you pay for them again each turn.\n- **No web search, no file store, no code sandbox**, unless you add them.\n- **No mobile app, no support, no history.**\n- **A bill instead of a price.** Which is the next lesson, and it is the one that goes wrong.\n\n## Getting started for nothing\n\nMost providers give new accounts free credits, typically $5 to $10, and some free tiers on developer platforms are generous enough for real personal use. Several hosted providers of open models offer free tiers as well. Between them you can do this whole module without paying anything.\n\nThe condition is the usual one: free tiers frequently permit the provider to use your inputs to improve the service, where the paid API generally does not. If you are experimenting with your own text, that is a fair trade. If you are experimenting with a client's contract, it is not."},"check":{"question":"A developer switches the base URL from a hosted provider to a local model and the same script keeps working, but a thinking-budget parameter they were passing is ignored. Why?","options":[{"text":"Local models cannot run in thinking mode, so the parameter has nothing to act on.","correct":false,"tempting":"Attributes to local execution a limit that is about the interface, since open reasoning models do run locally and expose their own controls."},{"text":"The base URL change did not carry the API key, so the request fell back to default settings.","correct":false,"tempting":"Invents an authentication failure that would have returned an error rather than a working answer with one setting missing."},{"text":"The shared format covers common fields; vendor-specific controls are extensions others do not implement.","correct":true},{"text":"Parameters are validated by the client library, which silently drops any field the provider's documentation does not list.","correct":false,"tempting":"Places the behaviour in the client library, when it is the receiving endpoint that ignores fields it does not recognise."}]},"prev":{"slug":"web-app-phone-app-desktop-app","title":"The web app, the phone app and the desktop app","url":"https://addaly.com/learn/choosing-your-tools/web-app-phone-app-desktop-app"},"next":{"slug":"keys-and-spend-caps","title":"Keys, spend caps, and the bill nobody wants","url":"https://addaly.com/learn/choosing-your-tools/keys-and-spend-caps"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'Your first API call', in Choosing and Using the Tools. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/choosing-your-tools/first-api-call (Accessed: 13 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"Your first API call","courseTitle":"Choosing and Using the Tools","module":{"index":3,"slug":"the-routes-in","title":"The routes in"},"answer":null,"keyIdea":"An API request is a model name, a list of role-tagged messages and a few settings, and because most providers accept the same format, moving between vendors or to a local model is usually a change of two lines.","hero":{"kind":"plate","image":null,"alt":null,"caption":null},"blocks":[{"t":"h2","id":"why-this-is-worth-thirty-minutes-even-if-you-are-not-a-progr","runs":[{"text":"Why this is worth thirty minutes even if you are not a programmer"}]},{"t":"p","runs":[{"text":"The API is the route where you pay for what you use rather than a flat monthly fee, where you can pin a model version, where you choose the system prompt, and where nothing about the product layer is decided for you. For a light user it is often a tenth of the subscription price. For anyone processing more than a handful of items it is the only sensible route."}]},{"t":"p","runs":[{"text":"You do not need to write software to use it. Free chat front-ends, covered two lessons from now, take a key and give you a chat window. But it helps enormously to see what one request looks like, because then the whole architecture stops being mysterious."}]},{"t":"h2","id":"the-request","runs":[{"text":"The request"}]},{"t":"p","runs":[{"text":"Every major provider accepts something close to this shape. Sign up, create a key in the console, then:"}]},{"t":"code","lang":"bash","label":"Bash","text":"curl https://api.openai.com/v1/chat/completions \\\n  -H \"Authorization: Bearer $OPENAI_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"model\": \"gpt-4o-mini\",\n    \"messages\": [\n      {\"role\": \"system\", \"content\": \"You are terse. British spelling.\"},\n      {\"role\": \"user\",   \"content\": \"Three risks of a fixed-price contract.\"}\n    ],\n    \"temperature\": 0.3\n  }'"},{"t":"p","runs":[{"text":"That is the whole thing. A model name, a list of messages with roles, and a couple of settings. In Python:"}]},{"t":"code","lang":"python","label":"Python","text":"from openai import OpenAI\nclient = OpenAI()                      # reads OPENAI_API_KEY from the environment\nr = client.chat.completions.create(\n        model=\"gpt-4o-mini\",\n        messages=[{\"role\": \"user\", \"content\": \"Summarise this in 40 words: ...\"}])\nprint(r.choices[0].message.content)\nprint(r.usage)                         # prompt_tokens, completion_tokens"},{"t":"p","runs":[{"text":"Two things in there matter more than they look. The "},{"text":"system","b":true},{"text":" role is the layer that consumer products fill in for you and you now control. And "},{"text":"r.usage","code":true},{"text":" prints exactly what you were charged for, which makes cost concrete rather than theoretical from the first minute."}]},{"t":"h2","id":"the-convention-that-makes-models-interchangeable","runs":[{"text":"The convention that makes models interchangeable"}]},{"t":"p","runs":[{"text":"That request format started at OpenAI and became a de facto standard. Most providers and nearly every local runner now accept it, which means switching models is often a change of two lines:"}]},{"t":"code","lang":"python","label":"Python","text":"client = OpenAI(base_url=\"https://api.anthropic.com/v1/\",  api_key=A_KEY)\nclient = OpenAI(base_url=\"https://openrouter.ai/api/v1\",   api_key=R_KEY)\nclient = OpenAI(base_url=\"http://localhost:11434/v1\",      api_key=\"ollama\")"},{"t":"p","runs":[{"text":"The last line is a model running on your own laptop, answering the same code. This compatibility is the single most valuable thing about the API route, because it makes your work portable in a field where products are withdrawn regularly."}]},{"t":"p","runs":[{"text":"Compatibility is not perfect. Vendor-specific features (thinking budgets, caching controls, certain tool formats) usually need that vendor’s own library. The common path works everywhere; the interesting features do not."}]},{"t":"h2","id":"reading-the-response","runs":[{"text":"Reading the response"}]},{"t":"p","runs":[{"text":"The reply comes back as JSON, and three fields in it are worth knowing by name. "},{"text":"choices[0].message.content","code":true},{"text":" is the answer. "},{"text":"usage","code":true},{"text":" is the token counts you were billed for. And "},{"text":"finish_reason","code":true},{"text":" tells you "},{"text":"why","i":true},{"text":" the model stopped: "},{"text":"stop","code":true},{"text":" means it finished naturally, "},{"text":"length","code":true},{"text":" means it hit the maximum output you allowed and was cut off mid-sentence."}]},{"t":"p","runs":[{"text":"That last one explains a complaint people bring to support constantly: answers that end halfway through a word. It is almost never the model failing; it is a "},{"text":"max_tokens","code":true},{"text":" setting somewhere, either yours or the front-end’s default. Raise it, or ask for a shorter answer, and the truncation goes away."}]},{"t":"h2","id":"what-it-does-not-give-you","runs":[{"text":"What it does not give you"}]},{"t":"p","runs":[{"text":"Be clear about what you are giving up, because people are sold the API as strictly better and it is not."}]},{"t":"ul","items":[[{"text":"No memory.","b":true},{"text":" Every request is independent. A conversation exists only because you resend the previous messages, and you pay for them again each turn."}],[{"text":"No web search, no file store, no code sandbox","b":true},{"text":", unless you add them."}],[{"text":"No mobile app, no support, no history.","b":true}],[{"text":"A bill instead of a price.","b":true},{"text":" Which is the next lesson, and it is the one that goes wrong."}]]},{"t":"h2","id":"getting-started-for-nothing","runs":[{"text":"Getting started for nothing"}]},{"t":"p","runs":[{"text":"Most providers give new accounts free credits, typically $5 to $10, and some free tiers on developer platforms are generous enough for real personal use. Several hosted providers of open models offer free tiers as well. Between them you can do this whole module without paying anything."}]},{"t":"p","runs":[{"text":"The condition is the usual one: free tiers frequently permit the provider to use your inputs to improve the service, where the paid API generally does not. If you are experimenting with your own text, that is a fair trade. If you are experimenting with a client’s contract, it is not."}]}],"check":{"question":[{"text":"A developer switches the base URL from a hosted provider to a local model and the same script keeps working, but a thinking-budget parameter they were passing is ignored. Why?"}],"options":[{"text":[{"text":"Local models cannot run in thinking mode, so the parameter has nothing to act on."}],"correct":false,"tempting":[{"text":"Attributes to local execution a limit that is about the interface, since open reasoning models do run locally and expose their own controls."}]},{"text":[{"text":"The base URL change did not carry the API key, so the request fell back to default settings."}],"correct":false,"tempting":[{"text":"Invents an authentication failure that would have returned an error rather than a working answer with one setting missing."}]},{"text":[{"text":"The shared format covers common fields; vendor-specific controls are extensions others do not implement."}],"correct":true,"tempting":null},{"text":[{"text":"Parameters are validated by the client library, which silently drops any field the provider’s documentation does not list."}],"correct":false,"tempting":[{"text":"Places the behaviour in the client library, when it is the receiving endpoint that ignores fields it does not recognise."}]}],"order":[3,2,0,1],"why":null},"prev":{"slug":"web-app-phone-app-desktop-app","title":"The web app, the phone app and the desktop app","minutes":8},"next":{"slug":"keys-and-spend-caps","title":"Keys, spend caps, and the bill nobody wants","minutes":8}}}