> ## Documentation Index
> Fetch the complete documentation index at: https://alguna.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Rate card sources

> Feed a rate card from a price list: fetch it from a URL, push it from your system or upload it, and choose which changes publish at once and which wait for review

A **source** feeds a [rate card](https://alguna.com/docs/rate-cards/overview) from a price list that another system owns. Alguna reads the list, turns each price into a cell of one usage entry, and publishes or drafts a [phase](https://alguna.com/docs/rate-cards/phases) with the changes. Use a source when your rates already live in a file, a supplier feed or your own pricing service, so that nobody types them in twice.

A card has at most one source. A price list source prices one usage entry of the card. A card can instead follow another card. That is also a source, and [Followers](https://alguna.com/docs/rate-cards/followers) describes it.

You set up a source in the dashboard, on the rate card's source tab. The public API has one source endpoint: the push endpoint for your system to send its price list.

> [!NOTE]
>
> Rate cards are available on request. See [Rate cards](https://alguna.com/docs/rate-cards/overview) to turn them on. Requests carry `Authorization: Bearer` with your API key and an `Alguna-Version` header.

***

## Ways to feed a card

| Feed | How the price list arrives | Fetch trigger in the history |
| - | - | - |
| Fetch from a URL | Alguna fetches an HTTPS URL on a schedule, or when you select **Fetch now** | `scheduled`, `manual` |
| Push from your system | Your system sends the list to the push endpoint | `api` |
| Upload a file | A person uploads the list in the dashboard | `upload` |
| Another rate card | The card copies each phase of another card | `upstream` |

A source that receives pushes also accepts uploads. Pushes and uploads follow the same rules. When you change a source's settings, Alguna applies its last price list again with the new settings (trigger `rebase`).

***

## How a source reads a price list

A source reads JSON or CSV. Its mapping, which you set in the dashboard, says:

* **Records.** Where each record is in the list, and which field or column holds its id, its group and its prices. A CSV source matches columns by their exact header text.
* **Selection.** Which groups and records become cells.
* **Cells.** Which dimension value each record gives, and how many metric units each price is quoted for. A price quoted per 1,000,000 tokens becomes a rate per token.
* **Markup.** The percent to add to the price list's cost. One band is a flat markup. More bands make graduated tiers. Rules can give some records a different markup.

Example: a CSV source for the `Tokens` entry of Token Standard reads `model` as the record id, `region` as the group, and `input_per_million` as a price quoted per 1,000,000 tokens, with no markup.

```text theme={null}
model,region,input_per_million
orion-pro,us,3.00
orion-pro,eu,3.30
orion-mini,us,0.50
orion-mini,eu,0.55
```

This list makes four cells. `orion-pro` in `us` costs 3.00 / 1,000,000 = $0.000003 per token. `orion-mini` in `eu` costs 0.55 / 1,000,000 = $0.00000055 per token.

Alguna strips a UTF-8 byte-order mark at the start of a file, as Excel writes one.

***

## Fetch from a URL

* The URL must use HTTPS and cannot hold a user name or password. Alguna refuses a URL that resolves to a private or internal address.
* Alguna fetches on a schedule from every 15 minutes to once a day. The default is every hour.
* You can add one secret header, for example an API key for the feed. Alguna stores its value encrypted and never shows it again. If you change the URL to another host, Alguna drops the header, so enter it again.
* Alguna sends the feed's last `ETag` with each fetch. If the feed answers that nothing changed, the fetch outcome is `not_modified`.
* The response body can be at most 20 MB.

After a failed fetch, Alguna waits longer before it tries again. The wait doubles with each failure in a row, up to 24 hours. After five failed fetches in a row, the source pauses. See [Paused sources](#paused-sources).

***

## Push from your system

Send your whole current price list as the body:

```text theme={null}
POST /rate-card-sources/{id}/price-lists?as_of=2026-10-19T10:00:00Z
Authorization: Bearer $ALGUNA_API_KEY
Content-Type: text/csv
```

The `{id}` is the source's id, which the source tab shows with the endpoint.

| Rule | Value |
| - | - |
| `Content-Type` | `application/json` or `text/csv`. It must match the format the source reads. Any other type gets 415. |
| Body size | 1 byte to 10 MB |
| Cells | At most 2,500 cells from one list |
| Pushes | One applied push a minute for each source |
| `as_of` | Optional, RFC 3339. The time your list was current. The default is the time the push arrives. At most 5 minutes after the server's time. |

The API key needs the permission to manage rate cards.

### Response

```json theme={null}
{
  "fetch_id": "rcdsf_0000000000000001",
  "outcome": "published_and_drafted",
  "published_phase_id": "rcdp_0000000000000005",
  "draft_phase_id": "rcdp_0000000000000006",
  "summary": {
    "records": 4,
    "cells": 4,
    "applied": 1,
    "held": 1,
    "unchanged": 2,
    "issued_invoices_overlapping": 0
  }
}
```

In this example, the card has the rates of the list above, and the source applies changes of up to 10% at once. The new list changes `orion-mini` in `eu` from 0.55 to 0.58, which is 5.45% more, so that change publishes. It changes `orion-pro` in `us` from 3.00 to 2.50, which is 16.67% less, so that change waits in the draft. The other two prices did not change.

| `outcome` | Meaning |
| - | - |
| `published` | Every change published at once. |
| `drafted` | Every change waits in a draft phase. |
| `published_and_drafted` | Some changes published, and the rest wait in a draft. |
| `no_change` | The card already has every price in the list. |
| `not_modified` | A URL feed answered that nothing changed since the last fetch. |
| `failed` | The list could not be applied. `error` says why. |

`issued_invoices_overlapping` counts the issued invoices that the published phase starts before. They keep their rates. See [Phases](https://alguna.com/docs/rate-cards/phases#issued-invoices-keep-their-rates).

### An older push never wins

Each push has a time: its `as_of`, or the time it arrived. Alguna refuses a push that is older than the last applied push with 409, and stores nothing of it. The check runs again while Alguna holds the card, so two pushes that arrive together cannot pass each other. A failed push is not an applied push.

Example: Push A is as of 10:00:00. Push B is as of 10:00:01. B applies first. When A arrives, Alguna refuses it, so B's prices stay.

### One push a minute

A source applies at most one push or upload a minute. A push less than a minute after the last applied push gets 429 with a `Retry-After` header, the seconds left in that minute. Alguna stores nothing of the refused push.

When you get 429, wait, then send your newest list. Do not queue the refused list: the newest list already holds its changes.

Example: Push A applies at 10:00:00. Push B arrives at 10:00:15 and gets 429 with `Retry-After: 45`. At 10:01:00, your system sends push C, its newest list, and C applies.

### Empty and oversized lists fail

A list that reads no rows, or that makes more than 2,500 cells, fails with a reason. It never reports `no_change`. Alguna keeps the body in the fetch history, so you can see the list that failed. Examples of reasons:

* "No rows read: the header has no "model" column"
* "No rows read: none of the 579 rows has a record id"
* "Too many cells: the price list makes 3100 cells and a source can price at most 2500"

Other refusals, such as a wrong `Content-Type`, an empty body or a push to a source that fetches from a URL, return an error status and record no fetch.

***

## Pricing policy

The policy says which changes publish at once and which wait in a draft phase for review.

| Policy | What publishes at once | What waits for review |
| - | - | - |
| Apply small changes automatically (`auto_within`, the default) | A change within your limit. The default limit is 10%. | A bigger change, a new price, a change to volume tiers, and a change from a price of zero |
| Hold every change for review (`review`) | Nothing | Every change |
| Apply every change automatically (`auto`) | Every change | Nothing |

More rules:

* A change that publishes at once takes effect at the time of the fetch or push.
* If a published phase that sets the source's entry starts later than now, every change waits for review.
* People who can manage rate cards get an in-app notification when the changes that wait for review change.
* A source keeps one draft for review. If a person edits that draft, the source stops adding new changes to it.
* When the price list stops giving a cell, the cell keeps its last price until a person removes it. A price that is missing, negative or unreadable also keeps the current price.

Review the draft and publish it like any phase. If the card has followers, the review shows every card of the chain. See [Followers](https://alguna.com/docs/rate-cards/followers#one-review-for-the-chain).

***

## Paused sources

A source pauses after five failed fetches, pushes or uploads in a row. A paused URL source stops fetching on its schedule. People who can manage rate cards get an in-app notification that the source paused.

To resume, a person who can manage rate cards does one of these:

* Selects **Resume** on the source tab. A URL source then checks the feed again with its saved settings.
* Fixes the source settings and saves them.
* For a URL source, selects **Fetch now**. A fetch that succeeds resumes the source.
* For a source that receives pushes, pushes or uploads a new price list. A list that applies resumes the source.

A refused push (409 or 429) or a request error stores nothing, so it does not count as a failure.

***

## Fetch history

Each fetch, push and upload adds a row to the source's fetch history. The row shows the trigger, the outcome and the counts. It also keeps up to 20 cells that wait for review or keep their current price, the ones that most need a look. The push response's `fetch_id` names its row.

Alguna keeps the body of each price list it receives. A body that no phase came from is deleted 90 days after the last fetch that received it.

***

## Limits

* A source prices one usage entry. Fees come from a person's phase or from a followed card.
* A source has at most one secret header.
* A list can make at most 2,500 cells.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.