Authentication
Every request to the Hydra API requires an API key passed in the Authorization header.
curl https://api.hydrajs.dev/v1/products \
-H "Authorization: Bearer sk_live_your_api_key"
API keys
When you create a project, you receive four keys:
| Prefix | Type | Environment |
|---|---|---|
sk_live_ |
Secret | Production |
sk_test_ |
Secret | Test |
pk_live_ |
Publishable | Production |
pk_test_ |
Publishable | Test |
Each key is 40 characters: an 8-character prefix followed by 32 random alphanumeric characters.
Keys are shown once at creation time. Store them somewhere secure. They cannot be retrieved later.
Secret vs publishable
Secret keys (sk_*) have full access to every endpoint. Use them in server-side code only. Never expose them in a browser, mobile app, or client-side bundle.
Publishable keys (pk_*) are safe to use in client-side code. They can:
- Read products, collections, and shipping rates
- Create and manage carts
- Create checkouts
- Query search
They cannot create, update, or delete resources like products, orders, or webhooks. Attempting a write operation with a publishable key returns a 403:
{
"error": {
"code": "forbidden",
"message": "Key does not have permission for this action."
}
}
Test mode
Test mode gives you an isolated environment with separate data. No real payments are processed, no webhooks fire to production URLs.
The environment is determined by the key prefix. Use a _test_ key and you’re in test mode. Use a _live_ key and you’re in production. There’s no separate flag or header to set.
# This hits test data
curl https://api.hydrajs.dev/v1/products \
-H "Authorization: Bearer sk_test_..."
# This hits live data
curl https://api.hydrajs.dev/v1/products \
-H "Authorization: Bearer sk_live_..."
Products, orders, customers, and all other data are completely separate between test and live environments.
Error responses
Missing or invalid key
Status 401:
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key."
}
}
Insufficient permissions
Status 403 (e.g., publishable key on a write endpoint):
{
"error": {
"code": "forbidden",
"message": "Key does not have permission for this action."
}
}
Rate limits
Requests are rate-limited per project using a sliding window.
| Plan | Requests per minute |
|---|---|
| Free | 60 |
| Pro | 600 |
Every response includes rate limit headers:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1692374520
When the limit is exceeded, the API returns a 429 with a Retry-After header:
{
"error": {
"code": "rate_limited",
"message": "Too many requests."
}
}
Monthly quota
Each plan includes a monthly request quota. When exceeded, the API returns a 429:
{
"error": {
"code": "quota_exceeded",
"message": "Monthly API quota exceeded."
}
}
| Plan | Monthly quota |
|---|---|
| Free | 2,000 |
| Pro | 100,000 |
A usage.warning webhook event fires at 80%, 90%, and 100% of your quota.
CORS
CORS headers are applied only to requests made with publishable keys — secret keys are server-side only and don’t need CORS.
To allow browser requests from your storefront, add your domain(s) to Allowed Origins in your project settings (or via the Store API). Only exact-match origins are accepted:
https://mystore.com
https://staging.mystore.com
Set a single * entry to allow requests from any origin. When * is configured, the API reflects the actual Origin header back in Access-Control-Allow-Origin (rather than sending a literal *), which is compatible with credentialed requests.
If the requesting origin is not in the allowed list, no CORS headers are returned and the browser blocks the response.
Allowed methods and headers
Access-Control-Allow-Methods: GET, POST, PATCH, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type, X-API-Key
Preflight
The API handles OPTIONS requests before authentication, so preflight checks succeed without an API key.
Best practices
- Never commit keys to version control. Use environment variables.
- Use publishable keys on the client. Secret keys belong on the server.
- Use test keys during development. Switch to live keys when you deploy.
- Monitor
lastUsedAt. Identify and remove unused keys.