AI
Your app can call an AI model — read a photo of a receipt, answer questions from your own data, summarise a block of text — without you ever signing up with a model provider or handling an API key.
Settings → AI is where you turn it on and watch what it costs.
What turning it on does
Enabling adds one file to your project, lib/ai.ts, and gives the project a token of its own. From then on the AI knows the capability exists and uses it when you ask for something that needs it.
What it does not do is add a feature to code you already have. If your app already shows a chat box that does nothing, enabling AI will not make it start answering — the chat box needs one more prompt. Enabling is the ingredient; the recipe is still a prompt.
Ask for an AI feature before enabling and what you get back depends on how much of the request survives without the model.
If the model call is the request — "a chatbot for my products", "scan this receipt" — you get an answer, not a build. It tells you the feature is possible and that AI needs switching on first, and nothing is written. A chat box that sends a message and cannot answer is not a head start; it is the same work paid for twice, once now and again after you enable.
If the model is one part of something larger — an expense form that also scans the receipt — the rest gets built, because a form is useful on its own. Only the scan step waits.
Either way it will not guess a provider, install an AI SDK, or leave a placeholder key behind. That last one is why this is careful: a placeholder compiles, passes every check, and returns an authentication error the first time a real person uses it.
The three things it is good at
Reading a document. A photo or scan goes in, structured data comes out — merchant, date, total from a receipt; name and address from an ID card. Your app then shows those values in a form for a human to confirm before anything is saved. The model suggests; your code decides.
Answering from your own data. "Which products are low on stock?" works because your app fetches the rows first and hands them to the model as context. The model never touches your database and never writes a query. That is what keeps one customer from asking a question that returns another customer's rows.
Writing and sorting text. Summaries, categories, drafts, tone changes. The ordinary case, and the cheapest.
Ask for any of these in plain language. You do not need to mention models, providers, or keys — and if you do name one, it will be ignored, because the choice is not yours to make here.
Changing data from a chat
"A chatbot that can add a product" is a normal thing to ask for, and it works — but not by letting the model touch your database. The model returns a decision ("create, with these fields"); your code checks that decision and runs the write itself. That is what keeps one customer from talking their way into another customer's rows.
Two things follow from it. The confirmation your chat shows is written by your code after the write succeeds, never by the model in advance — otherwise a failed save still reads as "Saved!". And when a field is missing, the reply asks for it rather than guessing.
What it costs
Every call spends credits from the same balance as your AI runs. There is no separate AI bill and no separate AI balance.
The panel shows today's spend against a daily cap and this month's total. The daily cap is the number worth watching: it is the one limit you can hit twice in a week. When it is reached, AI calls in your app answer with a "too many requests" error until the next day (UTC) — your app keeps running, only the model calls stop. Buying top-up credits does not lift this cap — it is a runaway brake rather than a quota, and it clears on its own the next day.
You can raise or lower the cap for a project, or clear the field to go back to the platform default. Setting it low is the safest way to try an idea you are not sure about.
A public feature spends your credits, not your visitors'. A chatbot on a page anyone can open is a page anyone can run up a bill on. Ask for it to be behind a login, or rate-limited, and say so in the prompt — the AI knows how to do both.
The token
Your project has a token that identifies it to the platform. Three things about it are worth knowing.
It lives on the server. It is never sent to a browser, and it must never appear in code that ships to one. If it does, the platform's checks will fail the run and tell you — a token in a page is a token every visitor can read and use.
It is shown once. Enabling or rotating displays it a single time as a copy for your records. It has already been written into your project's environment, so there is nothing for you to paste anywhere.
It can be replaced in one click. Rotate token issues a new one and invalidates the old immediately. Your deployed app keeps working, because the new value is written into its environment too. Do this the moment you suspect a copy got out.
Using your own provider instead
The helper speaks the standard OpenAI wire format, so any compatible provider works. Set these three in Env Variables, or in the exported app's own .env:
POLEVED_AI_URL=https://api.openai.com/v1
POLEVED_AI_TOKEN=<your provider key>
POLEVED_AI_MODEL=gpt-4o-mini
Change the URL and the token together. Pointing the URL at another provider while leaving the Poleved token in place sends a Poleved credential to somebody else's server. Both or neither.
When you go this route, calls no longer spend Poleved credits — you are billed by that provider directly.
When you export
Exporting to GitHub or downloading a ZIP takes lib/ai.ts with it, and the generated .env.example names all three variables. What it does not take is the token, because .env files are never exported. Fill in your own provider's details and the exported app works standalone.
Limits worth knowing
- One model family, chosen by the platform. You cannot pick a vendor per project. The panel lists the models you may request, and a prompt asking for a different one is refused rather than silently substituted.
- Images in, text out. The model reads pictures and writes words. It does not generate images.
- Mobile calls the web side. Your Expo app never calls a model directly — it calls a route in your web app, and that route does the work. That is what keeps the token off the phone.
- No memory between calls. Each request stands alone. A chat that remembers earlier turns works because your app sends the earlier turns along, not because the model recalls them.
- No tool calling. A request that sends
toolsorfunctionsis refused with a clear error, not answered as ordinary text. A model with no tools describes calling one and confirms the result — nothing is written, and the app reads as if it worked. Use the decision pattern above instead.