# Provider setup — BetsAPI

HelixOdds processes **your** provider data with **your** credential. You keep the
account; we do the processing.

## Why it works this way

The alternative would be us holding one provider account and reselling what it
returns. We do not do that, for two reasons. It would make your data licence
ours to negotiate rather than yours, and it would make one account's quota a
shared resource that any customer could exhaust.

So: you connect your own credential, your processing runs in your own workspace,
and your provider calls count against your own plan.

## Connecting

In the admin panel, on your client:

1. **Provider** → BetsAPI
2. paste your credential
3. **Test connection**

The status moves through:

```
UNCONFIGURED → VERIFYING → CONNECTED
```

`VERIFYING` is not a delay before we trust it — it is the state in which we have
your credential and your provider has not yet confirmed it. We never report
`CONNECTED` on our own word.

Verification makes one cheap request: a single page of upcoming football. A valid
credential returns a list; an invalid one is rejected by the provider rather than
by us guessing at the shape of a key.

## What the statuses mean

| Status | Meaning | What to do |
|---|---|---|
| `UNCONFIGURED` | No credential stored. | Connect one. |
| `VERIFYING` | Stored, not yet proven. | Run Test connection. |
| `CONNECTED` | Proven, and the last upstream call succeeded. | Nothing. |
| `DEGRADED` | It worked before and recent calls are failing. | Usually the provider. Watch it; processing continues. |
| `INVALID_CREDENTIAL` | The provider rejected it. | Replace the credential. |
| `DISABLED` | Switched off. | Enable it. The credential is still stored. |

`DEGRADED` keeps processing deliberately. A provider having a bad afternoon
should not become your outage, and a run of failures is not evidence your key is
wrong. Only a verification may ever brand a credential invalid.

## How your credential is stored

- **AES-256-GCM**, with a per-record nonce.
- The master key lives in the deployment environment or a secret manager —
  never in the database, never in a file beside the data.
- The ciphertext is **bound to its own connection record**, so a row copied into
  another account's registry fails to decrypt rather than being used on the
  wrong account.
- GCM authenticates: a modified ciphertext is an error, not a credential that
  decrypts into something we would then send upstream.
- `key_version` is stored with each record, so a new master key can be installed
  alongside the old one and records migrate without a downtime window.

Plaintext exists only in memory, for the duration of one upstream request. It is
never returned by an endpoint, never written to a log, never placed in an audit
entry, never put in an exception message, and never rendered into a page.

The panel and the API show only a **hint**: the length and the last four
characters. A credential shorter than twelve characters gets no characters at
all, because four of eight is half the secret.

## Rotating your credential

Paste the new one and verify. The connection returns to `VERIFYING` and then
`CONNECTED`. Your subscription, your features and your HelixOdds client token are
untouched — they are separate things.

Rotating your **HelixOdds client token** likewise does not affect your provider
connection. Two credentials, two jobs. See
[Authentication](authentication.md).

## Capabilities

What the adapter can prove it does:

| Capability | BetsAPI |
|---|---|
| `prematch` | yes |
| `live_odds` | yes |
| `live_stats` | yes |
| `timeline` | yes |
| `player_events` | **no** |

`player_events` is `false` because it is unproven. A player field appears in some
payloads; we have never established that events carry reliable player
attribution, so we do not advertise it. An unproven capability is `false`, not
"probably".

Capabilities are reported by the adapter itself and returned by
`GET /api/v1/account/provider`, so the list cannot drift from what the code can
actually do.

## Quota and batching

- The prematch endpoint accepts at most **10 fixtures per call**. Eleven returns
  a parameter error. This is a measured provider fact, not a tuning knob.
- Your monthly allowance belongs to your plan with the provider, not to this
  adapter. The panel can record it so an operator can see the budget your cycles
  are spending against.
- Football only (`sport_id=1`). Nothing else is fetched.

## Other providers

The architecture is provider-agnostic, and two more are declared:

| Provider | State |
|---|---|
| BetsAPI | implemented |
| The Odds API | interface declared, **not implemented** |
| OddspAPI | interface declared, **not implemented** |

A declared provider advertises no capabilities and refuses every call. It cannot
be connected. It exists so that "do you support X?" has an honest answer and so
that adding a provider is a new adapter rather than a rewrite — not so it can be
sold.

v1 supports **one** active provider connection per account. Running several at
once, falling back between them and blending their output are all deliberately
out of scope; the data model allows them, the write path refuses them today, and
a half-enforced rule is worse than a stated one.

## Provider rights

A technical capability is not a licence.

HelixOdds provides processing, normalisation, canonical mapping, deterministic
derivation, intelligence and API infrastructure. **The provider credential, and
the data it retrieves, are yours.** We do not own that data and we do not resell
it.

Provider contractual permissions are provider-specific and plan-specific. An
adapter being technically supported does not assert that every customer plan or
licence permits every redistribution use — whether you may show prices publicly,
redistribute them, or use them commercially is a question between you and your
provider, under your agreement with them.

Read your provider terms before redistributing anything. If your intended use is
unusual, ask them in writing. Nothing in this product encodes a legal conclusion
about your licence, and no part of the runtime decides what your agreement
permits.

See also: [Security model](security-model.md) ·
[Data contract](data-contract-v1.md)
