Getting Started with AI Access
From an empty project to the model's first answer. We will explain three terms you cannot do without, choose a provider and a model, get a key, run the first script, and look at what it costs and what to do when it does not work.
Three Terms You Need to Know
Before you write the first line, it pays to understand three words that this documentation keeps repeating.
Provider is the company that runs the language models and bills you for using them. AI Access knows five: OpenAI (famous for ChatGPT), Anthropic (the Claude models), Google (the Gemini models), the Chinese DeepSeek and xAI (the Grok models). You open an account with one of them.
Model is the particular brain you are talking to. Each provider offers several and they differ in price and ability:
small and cheap ones handle classification or summarizing, large and expensive ones cope with complex reasoning. In code a model
is identified by its name, such as gpt-5.6-luna.
API key is a long random string that tells the provider who is calling and whom to bill. It works as a password and a payment card at the same time.
Calling a model costs money. Not large amounts, an ordinary question costs a fraction of a cent, but the bill starts with the first call, so you will most likely have to top up credit or enter a payment card with the provider. Some providers give newcomers a small free credit.
Which Provider to Choose
The good news is that this choice is not fatal. Switching provider in AI Access is a one-line change, so if one does not suit you, you try another without rewriting the application.
For ordinary conversation they all do well. The differences are elsewhere:
- Breadth of capabilities. Do you want embeddings for search, batch processing or image generation alongside chat? Look at the capability table; OpenAI and Gemini have the widest reach.
- Price. Between the cheapest small model and the most expensive reasoning one there is a difference of roughly two orders of magnitude. DeepSeek tends to be markedly cheaper than the rest.
- Where the data goes. For company use it often comes down to where the data is processed and what the provider may keep for training. Look for the answer in their terms of service, not in a library's documentation.
- Availability. Not every provider is reachable from everywhere, and some features, such as Gemini's batch processing and image generation, require a project with active billing.
If you are unsure, start with the one you can pay easily and concentrate on the application itself. You can switch at any time later.
Which Model to Choose
Inside each provider you then choose among models. Simplified, three rules hold.
Start small. Models labeled flash, mini or lite are cheap and fast, and they are
plenty for summarizing, classification, rephrasing or pulling data out of text. A large model will not do these tasks much
better, only slower and at a higher price.
Reach for a large one only when the small one fails. You will know from the results: the model invents things, ignores instructions or loses the thread in a longer task. Only then does moving up pay off.
Reasoning models are a category of their own. Before answering they think, which costs time and extra tokens, but they handle tasks with several steps. How much thinking you want is set through reasoning effort; for simple questions feel free to turn it off.
A sensible starting point as of August 2026 looks like this:
| Provider | Chat model | Embedding model |
|---|---|---|
| OpenAI | gpt-5.6-luna |
text-embedding-3-small |
| Claude | claude-sonnet-5 |
– |
| Gemini | gemini-3.5-flash-lite |
gemini-embedding-2 |
| DeepSeek | deepseek-v4-flash |
– |
| Grok | grok-4.3 |
– |
Models change faster than any documentation can keep up with, so treat the table as a starting point rather than as law. A model name is an ordinary string in code, so a new model works the day it ships; whether yours still exists you check with listModels().
Getting the Key
Keys are issued in the provider's console. The procedure is the same everywhere: create an account, add a payment method or credit, and generate a new key in the API keys section. You will see the key only once, so store it right away; if you lose it, you generate another.
| Provider | Console |
|---|---|
| OpenAI | platform.openai.com |
| Claude | console.anthropic.com |
| Gemini | aistudio.google.com |
| DeepSeek | platform.deepseek.com |
| Grok | console.x.ai |
The same console holds the current price list and a summary of what you have spent so far. Right at the start it pays to set a monthly spending limit there; it is the simplest insurance against a mistake in a loop.
The First Script
This is a complete file you can save and run. The key is written in it directly, because right now the point is that it works on the first try. In a moment we will look at where it really belongs.
require __DIR__ . '/vendor/autoload.php';
$client = new AIAccess\Provider\OpenAI\Client('paste-your-key-here');
$chat = $client->createChat('gpt-5.6-luna');
$response = $chat->sendMessage('Explain in one sentence what dependency injection is.');
echo $response->getText(), "\n";
Run it from the command line with php file.php and in a moment you will see the answer. createChat()
opens a conversation over the chosen model, sendMessage() sends a message and waits for the answer.
The return value is not a string but a response object. Besides the text it tells you why the model stopped writing and what it cost.
Where the Key Belongs in Production
A key written in the code is fine for a first try and for nothing beyond that. Whoever obtains it spends on your account, and the most common leak is a key accidentally committed to git. Taking it back only looks possible: you can rewrite history, but once the commit has reached a server you must treat the key as leaked, because anyone could have copied it in the meantime. There is only one reliable fix, namely to issue a new key and revoke the old one.
So the key is written outside the code, most often into an environment variable. That is a named value handed to the application by the operating system, the hosting or Docker, so it lives in the server's settings rather than in the project's files. In PHP you read it like this:
$apiKey = getenv('OPENAI_API_KEY');
On your own machine you set it before running the script, on Windows with set OPENAI_API_KEY=..., on Linux and
macOS with export OPENAI_API_KEY=.... Hosting providers usually have a field for it in their control panel.
The other common route is a configuration file listed in .gitignore, so it is never versioned. In a Nette
application the key belongs in the local configuration and from there into the DI
container:
parameters:
openaiApiKey: '...'
services:
- AIAccess\Provider\OpenAI\Client(%openaiApiKey%)
That also buys you the nicest part of switching providers: the client arrives through the constructor and your class never learns which model it is talking to.
What It Costs
Providers bill by tokens, which are pieces of words. English text runs about four characters to a token, and languages with diacritics and inflection considerably fewer, so the same sentence costs more tokens in Czech than in English.
You pay separately for the input, meaning everything you send the model, and for the output, meaning what it writes. Output is usually several times more expensive than input. The thinking of reasoning models counts as output, even though you never see it.
We deliberately do not print actual prices here, because they change and would age quickly. You will find them on each provider's website under Pricing and in the same console where you issued the key. To give a sense of scale: a short question with a short answer on a small model costs a fraction of a cent, whereas summarizing long documents over and over with the largest reasoning model becomes a line you notice in the accounts. Between the cheapest and the most expensive model of the same provider there is usually a difference of two orders of magnitude, so the choice of model shapes your bill far more than optimizing the prompt.
What a particular call cost is reported by the response itself:
$usage = $response->getUsage();
echo 'input: ', $usage->inputTokens, "\n";
echo 'output: ', $usage->outputTokens, "\n";
echo 'total: ', $usage->getTotalTokens(), "\n";
Two further numbers deserve attention. reasoningTokens is what the model spent on thinking, and on reasoning
models it is often larger than the answer itself. cacheReadTokens, on the other hand, says how much of the input came
from the provider's cache at a fraction of the price; when you keep sending the same long system instruction, that number is your
friend.
When the First Call Fails
Errors are reported as exceptions and their type tells you what happened before you even read the message. This is how you catch them:
try {
$response = $chat->sendMessage('Hello!');
echo $response->getText();
} catch (AIAccess\ApiException $e) {
// the provider answered with an error; the code is the HTTP status
echo 'The API returned error ', $e->getCode(), ': ', $e->getMessage();
} catch (AIAccess\CommunicationException $e) {
// we did not get through, or the response was unreadable
echo 'The connection failed: ', $e->getMessage();
}
What the most common statuses inside AIAccess\ApiException mean:
- 401 – the key is wrong, missing, or belongs to a different provider.
- 404 – no model of that name exists. Usually a typo or a model the provider retired; print the list of models.
- 429 – you hit a rate limit, or your credit is empty. RetryClient can do the repeating for you.
- 500 and above – a problem on the provider's side, retrying makes sense.
Besides those two exceptions there are also AIAccess\UnexpectedResponseException, when a response does not have
the expected structure, and AIAccess\LogicException for a mistake in your own code, such as sending a conversation
without a single message. There is no point catching the last one; it is meant to crash and tell you.
The whole hierarchy, including how to handle errors once for the entire application, is covered by the chapter on error handling.
Where to Go Next
- Conversation – several messages in a row, the system instruction and reading the answer
- Options and reasoning effort – how much thinking you ask the model for
- Streaming – so the user is not staring at a blank page
- Error handling – what to do when the provider says no