Skip to content
Heimdallm
Provider console/dashboard
Documentation · For providers

The provider dashboard

Providers operate from the dashboard at your account, through the Provider console link. Its sections stand beside each other in the navigation, each at its own address: apply, publish, watch health, read earnings, configure payouts. The contract itself is Listing your models; this page is the surface you drive it from.

Applying

The application asks for what the marketplace displays: provider name, a slug (fixed once approved), website, contact email, headquarters, and links to a status page, terms and a privacy policy, plus a description. Payout details are not part of the application — they come later, after approval, from wallets already bound to an owner account (see settings below).

The marketplace may publish you under a name of its own choosing in place of the one you typed. Where it does, your dashboard shows both: the name you typed, and the one customers read beneath it. Only the displayed name changes. Your slug is what a caller's provider preferences name, and it does not move.

Once you are approved, only the marketplace can change your slug, on request. Your endpoints keep their ids through the change, so their uptime, timings, benchmark scores, price history and earnings stay with you. Your page moves to the new slug's URL, and a caller whose provider preferences name the old slug no longer matches you until they switch to the new one.

States, in the order you may meet them:

StateWhat you see and can do
PendingApplication under review. You can keep editing; a review follows.
RejectedThe review note explains why. Correct and resubmit — the review restarts.
ApprovedThe full dashboard.
DisabledEndpoints out of routing, sources no longer pulled. Contact support.

The review is administrative — identity, infrastructure and the honesty of what you intend to declare — not a judgement of your prices.

The stat strip

Approved, the dashboard opens on the figures that frame everything else: the platform share (and the share of gross you keep), the running month's net earnings, and how long you have been listed. A payouts held badge appears when payouts are paused for your account — usually a payout configuration that needs attention.

Sources

A source is what Heimdallm pulls your catalogue from: a base URL serving an OpenAI-compatible API (an Anthropic-dialect source is also supported), plus the credential Heimdallm should call you with. For an OpenAI-compatible source the base URL is the one an OpenAI SDK takes as base_url and ends in /v1; the model list is fetched from <base URL>/models unless you register a different models URL. An Anthropic-dialect source keeps the origin as its base URL, is called at <base URL>/v1/messages, and its model list defaults to <base URL>/v1/models.

  • Label — a name for the source (main, eu).
  • Base URL — where inference requests are sent. Serve TLS. An OpenAI-compatible source is called at <base URL>/chat/completions, <base URL>/embeddings, <base URL>/rerank, <base URL>/videos/generations and the other rails its models declare.
  • Source API — OpenAI-compatible or Anthropic-compatible; it decides how inference calls are shaped. An Anthropic-dialect source serves chat (streaming included) only — see operating. For a Dynamo server with OpenAI-style /v1 routes, select OpenAI-compatible and declare heimdall.upstream_dialect: "dynamo" in each model document.
  • Credential — the bearer secret Heimdallm presents to you. Write-only: after saving, only a hint is shown.

Pull now fetches your model list on demand and shows the run: outcome, how many models were seen, endpoints upserted and withdrawn, and every finding with the entry and field it concerns. Manual pulls are limited to one per source per minute. Below, each source keeps its recent pull history with the same detail.

Show the document this pull read opens the model list your models URL served, with a copy and a download of the exact bytes. Each entry is shown with its values as written, laid out for reading rather than byte for byte. Entries are listed by id with the findings reported against each, and an entry the Hugging Face fill completed lists every field the fill wrote, apart from what your document declares. It is the file to compare with your own when a finding is unexpected. Each source keeps the document of its 20 newest pulls; an older run still shows its findings and the SHA-256 of the body it read.

A run's findings are split into what is wrong and what was read for you. Filled from Hugging Face lists, per entry, the fields left empty that were read off the repository the entry links — and, where nothing was filled, which repository was asked and what it did not state. See what Hugging Face fills in for you.

Disabling a source stops its pulls; endpoints stand on their health alone. The pull schedule (1 minute to 24 hours) is configurable per source; the default is every minute.

Models

The endpoint table is the market's view of you: each model with its status — live, pending health, not ready, withdrawn, disabled — its health badge, quantization, context window, prices and when it was last seen. The prices are the ones your document declares, and where an entry declares discount_to_user the row says so. The charged figure also reflects an active catalogue or site promotion. It sets the price on the model page, the ceiling a customer's max_price is compared against, and the ordering between providers. Provider earnings use the larger of the endpoint and catalogue discounts before the platform cut; the marketplace funds any further site discount. This is where a listing's actual state shows up after a pull: a new entry arrives as pending health and goes live on probe success, no manual step; is_ready: false shows as not ready once two consecutive pulls have declared it, so a single flickered reading leaves a live endpoint where it is. An entry your document stops offering, or offers in a form that fails validation, is withdrawn on the pull that read the document — the second consecutive one for a live endpoint, the first counting as a false reading — and drops out of the table, counted beneath it with a control that shows the withdrawn ones; the finding sits against the entry that failed. Listing a valid entry again brings the endpoint back, at pending health, with no manual step.

Open an endpoint row to inspect Declared modalities, SKUs and capacity: the input and output modality objects, each pricing SKU with its unit and conditional overrides, and the capacity ceilings your source declared. This is the stored declaration, including entries the marketplace does not currently meter; the row's price summary distinguishes declared prices from what customers pay. Capacity here is a declared ceiling, not a measurement of free slots right now. An undeclared modality is shown separately from an explicitly empty list.

Opening a row shows the evidence behind its badges, the same account Health & errors gives: why the endpoint holds its health tier, what your own server answered the last failed probe and the path it was asked for, its capability verdicts and its benchmark scores, with Probe now beside them. A listing stuck at pending health is read and rechecked without leaving the table.

Catalogue discount

The catalogue discount control lets an approved provider owner set one percentage and an optional end date across every listed model. It does not edit the pulled document. Each endpoint's own discount still applies when it is larger. A change affects new requests; an admitted request keeps its recorded prices through settlement or recovery. Every change has an audit reason and a revision, so a stale form cannot silently replace a newer promotion.

Health & errors

Current health findings appear first, with the counted sample, probe-failure streak and applicable capability checks. Source-pull errors link to the source record. These describe the current state, independently of the period selected for historical traffic.

The chart starts with attempt outcomes. Select a metric to compare request volume, failure rate, first-token time, total latency or token usage by model or endpoint. Timing comparisons separate API types and offer median and p95 measurements. Total latency includes routing and retries, rather than isolating the endpoint's execution time. Counts include their sample sizes; missing measurements are not zero. The gap control can connect measured points without inventing observations. Idle count buckets within retention show zero.

More metrics includes requests offering tools and responses with a tool-call finish reason at the final serving endpoint. Automatic choices contribute to these activity counts. Tool-call response completion includes automatic, required and named choices, counting completed responses among those that emitted calls. Interrupted emitted-call responses are incomplete; text-only replies and missing observations are excluded. Observations belong only to the final attempt at the serving endpoint. The separate Recorded tool-call verdicts chart retains demand-compliance measurements. Completion observations do not affect health or routing, and do not measure tool execution. See Reading the charts for eligibility and gap semantics.

Errors are grouped by endpoint, caller type and recorded error metadata. Open a group to narrow the attempt log, then open an attempt for its diagnostics. Only served and endpoint-failed attempts count toward health; cancellations, request rejections and marketplace failures remain distinct. Customer error text is not retained because it can contain request content. Probe diagnostics can include the upstream message. The log and attempt-derived charts cover the seven-day retention window.

Models shows what you declared. Health & errors shows what your endpoints did with it: every request the marketplace put to them, and the measured figures those requests add up to — the same ones a customer reads when choosing between providers.

The expandable All outcomes comparison shows counts over the last day and the last week, your customers and the marketplace's own probes counted apart. Only served and failed attempts are evidence about your endpoint. A caller who walked away, a failure on the marketplace's own side, a request refused as malformed, and a base URL that resolves where the marketplace does not connect each belong to somebody else and reach neither your uptime nor your health tier; a capability check is a question about a declaration rather than a request anyone wanted served. They are all shown, counted apart, so a busy hour that reads badly can be traced to whose it was.

Measured endpoint figures & evidence shows your endpoints as the marketplace publishes them: uptime over the last day with the attempts that earned it, median time to first token, median response time, median output rate, and the share of demanded tool asks answered with a tool call. A blank cell is a window still under its sample gate, never a figure of zero — an endpoint no demanded tool ask has reached has no tool-call rate, and one that has never streamed has no first-token time. Embeddings endpoints never stream, so they carry a response time and no first-token figure at all.

Opening an endpoint shows the evidence behind its badge:

  • Why this health tier — how many of the newest counted attempts succeeded, beside the thresholds that reading is judged against, and the probe-failure streak that can mark an endpoint down before the sample moves. The last probe's own error is here too, which is usually the whole answer. Where a probe failed, a sentence names the path that was called and the status your own server answered it with, beside the status the marketplace recorded: an origin that routes a rail nowhere answers 404 where the marketplace records 502 provider_unavailable, and the path is what says which rail went unrouted. Probe now runs the check at once rather than at the next scheduled visit, at most once a minute per endpoint, so a fix is proved in seconds instead of waiting out a failure backoff.
  • Capability verdicts — the standing verdict on every capability the endpoint has been checked for, with what your engine actually said, and whether the latest check reached one. A verdict has three readings and the third is not a failure: a capability no check has reached a verdict on refutes nothing, and a latest check that could not be completed leaves the verdict before it standing, because an outage is not evidence about a declaration.
  • Benchmark scores — per dataset, once the endpoint has enough graded answers of its own for the figure to be a measurement rather than a small-n percentage. Scores are per endpoint, not per model: the same weights served at a different quantization do not answer the same exam the same way.

The attempt log is every attempt against your endpoints, newest first, filtered by endpoint, by caller, by outcome and by window. Each row carries the status the marketplace recorded and the error type beside it, what your own server answered under Answered with the path it was asked for, the timings and the token counts, and the id of the request it belonged to, which is what you and a customer can quote at each other. Request-level timings, token counts and earnings belong to the serving endpoint; failed attempts do not inherit another endpoint’s measurements.

A row opens the attempt's own record: the same record the customer reads about that request, holding everything measured that names nobody — the routing, every timing, every counter and every unit — beside the earning that request settled to.

Nothing here names a customer. No account, workspace, API key or application crosses to a provider, and there is nothing to redact besides: no prompt, no reply and no part of a request body is stored, here or anywhere. Attempts are kept for seven days and pruned, so the log is a window rather than an archive; the measured figures outlive it.

Routing

Models shows what you declared and Health & errors shows what your endpoints did. Routing shows what the marketplace did with the declaration: the requests an endpoint did not receive over the last seven days, and the rule that kept them away. It is the plan the router drew for each request, read back as counts.

Two kinds are listed for each endpoint, because they call for different changes:

  • Not considered — the endpoint was left out of the request's plan. Each line names the rule and what it was about: a parameter the endpoint does not declare, a value outside a declared range, a reasoning level that failed its capability check, a context window or output ceiling the request exceeded, a modality, a quantization or data policy left undeclared, a zero-data-retention approval still missing. Declaring what the engine honours is what changes the outcome.
  • Tried later — the endpoint was a candidate and another endpoint was tried first. The rule is the first one that separated the two: reported capacity (full, within the held-back quarter, or no fresh report), health tier, a higher price, or a measured throughput, first-token time or tool-call success that a caller's own sort preferred. Price is stated as a band over the endpoint tried first, never as another provider's rate.

Routed elsewhere is how many of a line's requests had another endpoint in the plan, which tells a request your endpoint lost from one nobody could serve.

A caller's own choice of provider is never counted, since it is not something a declaration can change. No caller, key or request body is stored: a line is a rule, the bare name it was about and a count, and a line under five requests in the window is not shown. Counts are folded in every thirty seconds, so a change reaches this section within about a minute.

Tips

Everything else on this page shows what you declared. Tips shows the other half: what the marketplace does with it, and which of your declarations do not hold when it asks. A misconfiguration usually costs a provider traffic long before anyone notices, and from your side of the wire there is nothing to see — an engine started without a tool parser serves ordinary requests perfectly while rejecting every agent request routed to it.

Tips cover your live endpoints and your pending ones alike. A listing that never passed its health check is the case with the most at stake — the whole endpoint rather than a share of its traffic — and it is the one where the rest of the dashboard shows a badge and no reason.

Nothing here affects your status, your rank in routing or your earnings. Each tip carries the evidence behind it, never a severity:

  • Measured — taken from a request sent to your endpoint, or from real traffic billed through it. A declared capability that does not hold appears here with the date and the endpoint's own words, as does a prompt cache serving tokens you have published no cache price for. Real traffic carries three more: a tools declaration whose measured share of answered tool requests has fallen under the floor routing holds it to, context-length refusals that named nothing about the request they refused, and streams arriving in too few chunk frames to demonstrate an output rate, beside an endpoint publishing none. A check your engine refuses for its size rather than for the parameter it carried reaches no verdict, and where the engine's own sentence names a window smaller than the max_context_length you declare, that figure appears here against your declaration: every check asks with your declared output budget, so a window declared above the engine's turns the whole round of checks into refusals of the ask's size. A check your front door answers with a server error reaches no verdict either, and three or more in a row over an hour or longer, on an endpoint whose health checks pass in between, appear here as the capability your deployment cannot complete an ask of: a server error refutes nothing, so nothing is withheld and requests needing it keep arriving. A reasoning level whose check succeeded and came back with no answer, no tool call and no reasoning appears here with the completion tokens it billed, because that is what a thinking model served without its reasoning parser returns, and the level is routed elsewhere until a check passes. An endpoint that declares image input is sent one solid red square on the same cadence and asked its colour; an engine that refuses the image appears here in its own words, and one that takes the part and answers without naming the colour appears after three such replies. Routing reads the declaration and keeps sending image turns here on its strength regardless of this check, so nothing is withheld here, and every caller who took the listing at its word gets the same. An endpoint that has never passed its health check appears here once three probes in a row have failed, with the streak, the last error your engine returned and when it is next due — a probe that failed on the marketplace's side counts towards neither. Requests refused before a socket was opened, because a base URL resolves off the public internet, appear the same way. An endpoint that renders carries two of its own: rendered output metered against no published rate for its billing unit, which are recorded as unpriced and earn nothing rather than billing at zero; and renders that ran out of time upstream before they finished, which hand the caller no partial answer at all — nothing streams on that rail — and are recorded as errors inside your uptime. Any unit consumed against a price your document does not publish appears here as the bill recorded it: seconds of audio decoded on a transcription endpoint with no per-second price on its audio input are charged nothing rather than billed at zero, so the customer paid nothing, nothing was earned, and a price declared later bills none of what has already gone out. The same bill read the other way prices the discount that never came: a cached_prompt price that no reply has exercised, because the bill discounts only what a reply evidences, so until a reply carries the count, every prompt token, served from cache or not, has billed at the prompt rate. And the mirror of the unpriced-unit rule: units your endpoint reports against no price of their own kind, cache-write tokens and reasoning tokens, which bill at the prompt and completion rates, with the counts as the replies recorded them.
  • Arithmetic — published numbers compared: two of your own declarations, or one of yours against what the checkpoint you link publishes about itself. An endpoint whose text output declares a max_length larger than its max_context_length takes the requests an endpoint with an honest ceiling refuses and then trims them, since routing filters on the ceiling and trims against the window; a ceiling equal to the window is the ordinary declaration and is not read against anything, because the trim is what happens to every request asking for more room than the prompt left. A cached_prompt price above your prompt price bills a prompt token your engine served from its own cache for more than the same token sent fresh, which is the one figure an agentic caller compares endpoints on. Where a model names a hugging_face_id, your declared max_context_length is compared against the window that repository's config.json implies, and any shortfall is stated, because a request needing more than you declare is routed elsewhere however small the gap — serving less than the checkpoint holds is also an ordinary answer, since a window is KV cache and the number is yours, so this is one to hide when the answer is your cards. An endpoint that renders is left out of that comparison: its prompt is conditioning text the drawing graph bounds, while the figure in the file is the positional ceiling of the language tower inside the checkpoint. That window is not always the max_position_embeddings the file prints: an XLM-RoBERTa checkpoint publishing 8,194 positions builds its position ids from pad_token_id + 1 and holds 8,192, so the evidence names the figure in the file and what came off it. The same repository is read for what it says about identity. Its creation date on the Hub is a floor under your created: a model is not released before the weights it is made from exist, so a release declared earlier than the base repository you name, or than the repository you load where you name none, is stated with both dates. Its model card names the repository it was made from and how, and a fine-tune, merge or adapter whose repository carries its base's name with something added to it is a modification of those weights: one listed with no base_model is read as a family of its own, and one listed under the base model's own id serves modified weights to every customer who asked for the base, since two providers publishing one id serve one model. A repository named nothing like its base is a release in its own right — an embedding model or a reranker trained on somebody else's backbone names that backbone the same way — and is read against none of this. Its config.json states the width the stored weights hold, so a quantization wider than that — bf16 over a W4A16 repository — is stated, while a narrower one is an ordinary load-time quantisation and says nothing; and its towers say which inputs it was trained on, so an image or audio input declared on an architecture that is a bare text decoder is stated too. Two of your own declarations are compared the same way: compliance.zdr: true beside a retention period or training use, and, across your whole document, one hugging_face_id listed under several model ids at one quantisation, which is one deployment the directory shows as several models. A base_model no model carries, on a listing your document groups, is read against its base_model_hugging_face_id: where exactly one family rooted at a model the directory lists records that repository, the tip names that family's id, because a listing groups under the base_model it declares exactly as written. A tip stating which family a model lists under goes only to the endpoint whose document owns that model's metadata, and not while the metadata is locked, because no other document's base_model moves it. An id spelled in a different case from the Hub's own resolves at every read and is stated as arithmetic on two strings; a repository the Hub shows nothing at is stated as measured, because the Hub answered.
  • Routing — not a fault at all. What the marketplace does with something you have not declared: a request asking for zero retention reaches only endpoints whose declared compliance.zdr: true has passed marketplace review, and one refusing endpoints that may train on prompts reaches only endpoints that declare data_policy.training either way — the two are read one at a time, so a declared false wins that traffic where a silence does not, because undeclared is treated as unknown rather than as permissive; a request naming the quantizations it accepts is routed away from an endpoint that declares none, and where you do not know what your engine loads, unknown is a value the field takes and shows; a model with no tags is left out of every tag filter in the directory; and prompt tokens served from cache bill at your full prompt rate while there is no cached_prompt price, which is the number agentic callers compare endpoints on. An endpoint that renders images or video and publishes no envelope takes no render request at all, because bounds are what a requested shape is matched against and there is no ceiling to assume in their place; one that publishes bounds and no output price lists with no render rate beside it. The directory labels each declared billing unit and shows no rate where none is published; and one that reports no capacity is attempted after every endpoint reporting a free slot, because reported capacity partitions the attempt order and there is nothing here to read. Four more read the repository or the document and state a convention rather than a fault: a release date months past the repository's creation, which reads as the day the weights were downloaded; a quantised repository, or a copy of one, linked with no base_model_hugging_face_id naming the released weights; a vision or audio tower the declaration leaves out, which routes no such request here; tool_choice, top_logprobs or structured_outputs declared without the field it is read beside; and a display name without the Author: Model Name prefix the directory is written in.

Some tips you will read and decide not to act on — an output ceiling you set deliberately, a data policy you will never declare. Ignore moves one out of the list into the ignored ones, where it stays readable, and Show ignored brings them back. Tip is wrong says the rule behind the tip is mistaken rather than your deployment; that one stays in the list, badged, and joins a queue an operator rules on, either upholding the tip or conceding the fix is owed on the marketplace side. Both answers are read by the marketplace and by everyone on your provider team, and Take answer back returns the tip to the list unanswered.

Neither answer stops a tip being derived, and ignoring one is measured against how strongly the finding was held when you answered. A tip you ignored as a routing note that traffic later proves comes back into the list, because reading a convention and leaving it is a different decision from reading a measurement and leaving it; evidence that weakens back to what you answered makes your answer apply again, and nothing is rewritten either way. A dispute never lapses like that. It is an argument about the rule rather than about how strongly the marketplace holds it, so stronger evidence sharpens the disagreement instead of settling it, and only an operator's verdict ends one.

Where a tip compares one of your declarations against something outside it, Fixed re-reads your models document and derives the tip again. The other tips carry no such control and say instead what would settle them — the next capability check, or the traffic and the capacity poll their evidence arrives on — because a control promising a refresh nothing acts on is the same failure as a tip that is wrong.

Capability checks run every six hours against endpoints that declare the capability — tools, structured_outputs, each declared enum value of reasoning_effort, and image input — and every half hour once the latest check failed, so a fixed engine is reinstated within the half hour rather than the six. Checks are billed as ordinary traffic. A failed check is never counted as downtime and never reaches your uptime or health tier — the endpoint serves every other request that day perfectly, and taking that traffic away would punish the requests it can serve for the sake of the ones it cannot. The same checks run against the marketplace's own reference provider on the same schedule.

Earnings

The money view: a month picker over the last twelve months showing gross, platform share, net and generations, with a per-model breakdown — exact decimal strings, matching what the ledger records.

Below the per-model breakdown, who pays the month: the same earnings split by the statement claiming each part of them, with the part no statement has claimed yet named as such rather than folded into a total. A month can appear under two statements, because a statement claims the earnings nothing has claimed when its period closes — so an earning settling after a payout is paid by the next statement instead of the one it missed.

Below it, statements: one per UTC calendar month, with gross, net, status and payout reference. A statement paying earnings from before its own period says so on the row. The statuses read open (the month is running or awaiting close), finalized (due for payout), held (payouts paused for your account) and paid — a paid statement carries its payout reference, which is the transaction receipt. The money mechanics — the 10% share, monthly close, USDC-on-Ethereum payouts to a deposit-proven wallet — are specified in Listing your models.

Members

Provider membership is separate from organization membership: owners and members, added by email of existing, verified accounts. Owners see everything including money and settings; the last owner can neither demote themself nor leave.

Settings

Two blocks, owner-only:

  • Payouts — pick the payout address from qualifying wallets: a wallet bound to an owner account that has made at least one credited deposit. Each candidate shows its qualification (bound + deposited, or no longer qualified — which blocks payouts until reconfigured). The contract wallet warning matters here: a Safe deployed on another network but not on Ethereum does not exist at that address for a payout.
  • Provider profile — the application fields again, editable, with the slug locked.

Next

  • Operating a source — pulls, health, capacity, dialects, and the common findings mapped to fixes.
  • Pricing & demand — how price steers routing, and how to be found.
  • A worked example — a real seven-model setup across six rails, configuration included.
SourcesThe model-list documents the marketplace pulls on a scheduleModelsEvery endpoint your documents publish, its status and its pricesHealth & errorsEvery request put to your endpoints and the figures they add up toRoutingThe requests your endpoints did not receive, and the rule that kept them awayTipsWhat the marketplace reads off your deployment that you can act onEarningsYour share of the traffic you served, by month and by statementCatalogue discountOffer one discount across every model in your catalogueMembersWho can operate this providerSettingsPayout wallets and the provider profilePerformance metricsProvider observability and monitoringIntegration guideConnect and operate inference capacity