# Partner keys and publish credentials

Source: https://opvs.ai/docs/guides/vendors/partner-keys

> The partner key that authenticates your publish calls, what it can and cannot do, and the credentials the CLI reads.

A **partner key** is a long-lived secret OPVS issues to your vendor. You send it with every write call to the registry. The registry checks it and pins the call to **your** vendor scope.

## What it looks like

```
opvs_pk_a1b2c3d4_<secret body>
└──┬──┘ └──┬───┘ └─────┬─────┘
  tag    prefix     secret
```

OPVS stores the prefix in clear text (to find the key fast) and only a bcrypt hash of the secret body. Nobody at OPVS can read your key back.

## How you get one

OPVS mints it for you and shows the raw key **once**, passed to you through a secure channel. To ask for one, write to vendors@opvs.ai with:

1. A label for where it will live, for example "acme production publish CI".
2. Whether it is a first key or a replacement.

If you lose it, the only recovery is a new key plus revoking the old one. See [Rotate a credential](https://opvs.ai/docs/guides/vendors/rotate-credentials.md).

## What it can do

Every call made with your partner key is scoped to your vendor.

**You can:** publish new versions under `@yourvendor/*`, revoke or flag a [required upgrade](https://opvs.ai/docs/guides/vendors/required-upgrades.md) on your own packages, upload your bundles, and run [harvest](https://opvs.ai/docs/guides/vendors/harvest.md) on workspaces that installed your packages.

**You cannot:** publish into another vendor's scope (refused with a scope mismatch), touch another vendor's packages, mint or revoke keys, or call the admin endpoints. OPVS staff use a separate platform key for those; you will never need it.

## Where to store it

```
OK  CI secret (masked + protected)        e.g. OPVS_PARTNER_KEY
OK  a secrets manager (Vault, AWS SM, 1Password)
OK  a gitignored .env file outside the repository, for local work
NO  source code, git history, chat, email, CI logs
```

A key that was committed, even for a moment, is compromised. Ask for a new one and have the old one revoked.

## The credentials a publish needs

What

Where it comes from

How the CLI takes it

Partner key

this page

`--admin-key <key>` or the `OPVS_MARKETPLACE_ADMIN_KEY` environment variable

Signing key

[your certificate](https://opvs.ai/docs/guides/vendors/signing-certificate.md)

`--private-key <file>`, an inline base64url string, or `@env:<NAME>`

Registry address

always `https://market.opvs.ai`

`--api-url https://market.opvs.ai`

You do **not** need an npm account or npm token. The CLI uploads your signed bundle straight to the marketplace; nothing is published to npm.

## On the wire

The CLI does this for you. This is what it sends:

```bash
# 1. ask for an upload URL for the bundle
curl -X POST "https://market.opvs.ai/api/v1/bundles/upload-url" \
  -H "X-Admin-Key: $OPVS_PARTNER_KEY" -H "Content-Type: application/json" -d @upload-request.json

# 2. PUT the signed tarball to that URL, then register the version
curl -X POST "https://market.opvs.ai/api/v1/registry/packages" \
  -H "X-Admin-Key: $OPVS_PARTNER_KEY" -H "Content-Type: application/json" -d @signed-manifest.json
```

The header is `X-Admin-Key` and the value is your partner key. Any failure (unknown key, revoked key, wrong scope) returns `403` with a one-line reason, and nothing is published.

Status

Meaning

What to do

`401` / `403`

key missing, unknown or revoked

check the variable is set; ask for a new key if it was revoked

`403` scope mismatch

the manifest's vendor is not yours

publish only under your own scope

`422`

the manifest or the security review refused it

see [Security review](https://opvs.ai/docs/guides/vendors/security-review.md)

## Revocation is immediate

When a partner key is revoked, the next call with it gets `403`. There is no cache window. The revoked key's record (prefix, dates, reason) is kept for audit.

## Next

[Rotate a credential](https://opvs.ai/docs/guides/vendors/rotate-credentials.md).
