Skip to content

Authentication

Every request carries an API key. Create one on the Developer page, or let a coding agent get one with a click from you.

View as Markdown

Every request carries an API key as a bearer token in the Authorization header. The key is a machine credential: it belongs to your organization, and no person signs in to use it.

API keys

curl -sS https://api.versionstory.com/v1/compare \
  -H "Authorization: Bearer vs_live_..." \
  -F "original=@v1.docx" \
  -F "modified=@v2.docx"

Getting a key

Keys are created in the Version Story web app, on the Developer page (the terminal icon in the sidebar, or app.versionstory.com/developer), under API keys. Issuing or revoking one requires the Developer permission on the organization.

  • Signing up gives you access. Create an account and you own a new organization with the Developer permission, so the page is there straight away. New organizations start on an API trial.
  • In an existing organization, a member who manages members can grant you the Developer permission from your entry in the organization's member settings.
The API keys tab of Version Story's Developer page, listing each key with its last-used and created dates
The API keys tab of Version Story's Developer page, listing each key with its last-used and created dates

The Developer page's other tabs are useful alongside the keys: Overview charts API activity and success rate and holds the zero-day retention setting, and Repository shows every document and redline the API has created.

Give the key a name that says what it serves — "Contract intake integration" reads better than "key 2" when someone audits the list a year later. The token is shown once, on creation, in a banner with a copy button. Store it before you dismiss the banner.

Getting a key from a coding agent

A coding agent setting up an integration (Claude Code, Codex, Cursor and the like) can get its own key, with one click from you and no copying. It opens Version Story in your browser, you sign in or register and click Allow, and the agent receives a new key and stores it where your secrets live. Quickstart with a coding agent is a prompt that has an agent do it, with the script it runs. Under the hood it is the OAuth authorization code flow with PKCE, for a native app on a loopback address (RFC 8252):

  1. The agent makes a PKCE pair (a random code_verifier and its S256 code_challenge) and a random state, and listens for one request at http://127.0.0.1:<port>/callback.
  2. It opens https://app.versionstory.com/developer/authorize with the query client_name, which becomes the key's name, redirect_uri, code_challenge, code_challenge_method=S256 and state.
  3. You sign in or register, and allow the request for your organization. Allowing it needs the Developer permission, as creating a key on the Developer page does.
  4. The browser brings a one-time code back to the agent's listener, and the agent redeems it within five minutes:
curl -sS https://api.versionstory.com/v1/api-keys \
  -H "Content-Type: application/json" \
  -d '{"code": "...", "code_verifier": "...", "redirect_uri": "http://127.0.0.1:53682/callback"}'
{
  "api_key": "vs_live_...",
  "name": "Claude Code on dana-laptop",
  "organization_id": "...",
  "organization_name": "Reyes LLP"
}

POST /v1/api-keys is the one call that takes no key. The redirect_uri must be exactly http://127.0.0.1:<port>/callback (or [::1]), with no query, and the same value the authorize page was given; a code is redeemed once. A code that is unknown, expired, already used, or sent with the wrong verifier or redirect is 400 INVALID_AUTHORIZATION_CODE.

The person who allowed the request is emailed that a key was created with their account, and the key list marks the key Created by sign-in, so a key allowed by mistake is easy to spot and revoke.

What a key is

A key looks like vs_live_{id}_{secret}, for example vs_live_9f3c…_R7x…, and works with https://api.versionstory.com.

A key belongs to the organization, not to the person who created it, so it keeps working when that person changes roles or leaves. Requests authenticate as the organization's service account: a machine identity that exists only to carry API work and has no sign-in of its own. That account is what every API-created comparison is attributed to and metered against. The member who issued the key is recorded as created_by_email, as an audit trail and nothing more.

Handling a key

  • The secret is shown once, at minting, and is never recoverable. Version Story stores only a SHA-256 hash of it. If you lose the key, you get a new one; nobody can read the old one back to you.
  • Treat it like a password. Keep it in a secrets manager or an environment variable, never in source control, and never in client-side code — a key in a browser bundle is a key the whole internet has.
  • An organization can hold several keys at once, and each one can be revoked on its own. Revocation takes effect on the next request. Rotate in this order: create the new key, deploy it, then revoke the old one. The other order leaves a window with no valid credential.
  • The key list shows each key's name, when it was created, and when it was last used, and marks revoked keys — enough to tell a live integration from one you can safely retire. Hover a key's Created date to see who issued it.

Auth failures

StatusCodeMeaning
400INVALID_AUTHORIZATION_CODEPOST /v1/api-keys only: the code is unknown, expired or used, or its verifier or redirect does not match
401INVALID_API_KEYMissing, malformed, unknown, revoked, or expired key
403API_KEY_ORG_MISMATCHThe key's service account is no longer operating in the key's organization

API_KEY_ORG_MISMATCH is deliberately loud rather than silent: honoring a request whose principal has drifted would attribute and bill the work to the wrong organization. Because a key's service account is derived from the organization itself, you should never see this in practice. If you do, issue a new key and revoke the old one.