how does it ask perplexity sonar?
Over the documented chat-completions endpoint. Perplexity was chosen first because it returns its sources as structured data: the source graph cannot be built from a surface that only returns prose, and guessing at which pages a model read is the part of this category that is currently all guesswork.
which door is this?
The api surface. It is not what a person typing into a browser sees, and the published gap between those two is larger than the noise this library is here to measure. A number collected here is a number about this door.
which endpoint, and why not the newer api?
Two routes answer, /chat/completions and /v1/sonar, and /v1/sonar is the one the reference documents. It is used for that reason: an undocumented route gets no deprecation notice, and the response shape parsed here is only specified for the documented one.
Sonar itself is soft-deprecated in favour of the Agent API, with no retirement date published anywhere. That migration is not made, because the Agent API's presets are unversioned by design: a preset name always resolves to the latest recommended configuration. An instrument whose units change under it when the vendor ships is not an instrument, so any move there has to pin an explicit model id rather than a preset.
what is read off a response?
The source list, from search_results and then citations. The changelog says the second was removed in favour of the first while the published OpenAPI for the same endpoint still declares it, so both are read and the current one first. A rename that went unnoticed would show up as "this question has no sources", which is a measurement claim made by accident.
The token counts, under either pair of documented names, and a name that cannot be found is recorded as unknown, never as zero, because zero tokens is a cost claim. The billed amount comes from usage.cost.total_cost, the one place the response schema documents it.
what has not been checked against a live key?
Every call this build has billed went to the other engine. Perplexity is sent max_tokens now, and the round that would prove it has not been bought. The per-search charge the response documents as usage.cost.request_cost is not read or stored yet: the schema a figure lands in is settled by a real response rather than by a specification, and this endpoint has never answered this build.
how do you get a key?
At the API portal, which is a different place from the chat product: open the API Keys tab, generate a key, and copy it then, because it is shown once. Pricing is pay as you go and their docs state no minimum purchase. A brand new account is Tier 0, which their documentation put at 50 sonar requests per minute when it was read on 31 July 2026, enough for everything in this repository.
Perplexity keys are reported to start with pplx-. That format is not stated anywhere in their own documentation, so lulu treats it as a hint and warns rather than refuses. A key starting sk- belongs to another provider and will be rejected by the endpoint.
what does perplexity sonar cost?
Read 2026-07-31 from docs.perplexity.ai/getting-started/pricing.
where is the key read from?
From the environment first, so a key exported for one command wins over a stored one: PERPLEXITY_API_KEY then LULU_PERPLEXITY_API_KEY. Then the OS keychain, under the service lulumelon and the account perplexity. Then ./.env and ~/.lulu/env, and nothing else, so a run can never quietly pick up a key from a directory you were not thinking about.
A key is checked with sonar, and that is also the model a command asks when no --model is given.
The key page is console.perplexity.ai. Keys starting pplx- are expected, which is a convention reported outside the provider, not stated in perplexity's docs as of 2026-07-31.