Skip to main content

Overview

Every protected endpoint in GRAIL takes a single header: x-api-key. There is one partner scope (PARTNER) — one key grants access to everything a partner can do (trades, redemptions, users). Keys are minted via challenge-response: you sign a short-lived message with your partner wallet’s private key, and exchange the signature for a key. GRAIL stores only a hash — raw keys are shown once. The two endpoints in the auth flow are the only /v1/* routes that do not themselves require authentication. They are rate-limited to 10 requests per minute per IP.

Prerequisites

Before you start, you need:
  • Your partner ID (UUID) — given to you by ORO at onboarding
  • Your partner wallet keypair — the private key that signs the challenge. This must correspond to a wallet registered under your partner (the wallet is the one ORO whitelists on-chain).
  • A way to sign a UTF-8 message with Ed25519 and produce a base64 signature. The snippet below uses tweetnacl.
The signature format is base64, not base58. Submitting base58 produces 400 invalid_signature. This is the most common onboarding mistake.

The flow at a glance

Challenges expire after 2 minutes. Complete signing and exchange before then.

Step 1 — Request a challenge

Response:
Save challenge_id and the full message string.

Step 2 — Sign the challenge message

Sign the message (UTF-8 bytes) with the partner wallet’s Ed25519 private key. Encode the signature as base64.
You can use any Ed25519 signing library in any language — tweetnacl is just the common JS choice. The only hard requirement is that the final output is base64 of the 64-byte signature.

Step 3 — Exchange the signature for an API key

Response:
api_key is shown only once. Store it somewhere you can retrieve it later (secret manager, encrypted env var). If lost, revoke it via Revoke API Key and mint a new one.

Step 4 — Verify the key works

Hit a protected endpoint. The denominations list is a safe one — read-only, no side effects:
If you get a JSON body with a denominations array, you’re authenticated. If you get 401 unauthorized, check that the header name is x-api-key (lowercase, with hyphen) and that you pasted the full key including the grail_partner_ prefix.

Managing keys

List your keys

Returns metadata for every key minted against your partner’s wallet (including revoked ones). Raw keys are never returned.

Revoke a key

Revocation is immediate and permanent. Use this when a key is compromised or no longer needed.
It’s common to mint a separate key per environment or per deployed service (e.g., prod-backend, staging-cron). Label them clearly via key_name — the list endpoint shows the label, which makes tracking easier.

Troubleshooting

Next steps

With your API key working, proceed to Creating & Managing Users.