Skip to Content
API ReferenceAuthentication

API Authentication

All Public API requests require authentication via API key. This page covers API key types, authentication methods, and security best practices.

API Key Types

Foir supports three types of API keys, each designed for different use cases:

Production Keys (pk_live_)

  • Returns published content only
  • Used in production frontend applications
  • Ignores preview parameter
  • Best for live websites and apps

Preview Keys (pk_preview_)

  • Returns latest draft content
  • Used for content preview and staging
  • Always returns latest version regardless of publish state
  • Best for preview deployments and editorial review

Development Keys (pk_dev_)

  • Returns any version based on parameters
  • Full control over version selection
  • Supports versionId, versionNumber, and versionState parameters
  • Best for development and testing

Authentication Methods

Include the API key in the x-api-key header:

curl -X POST https://api.foir.io/graphql/public \ -H "Content-Type: application/json" \ -H "x-api-key: pk_live_abc123..." \ -d '{"query": "{ resolveRoute(path: \"/\") { record { id } } }"}'

Query Parameter Authentication

For webhooks or scenarios where headers aren’t available:

curl -X POST "https://api.foir.io/graphql/public?apiKey=pk_live_abc123..." \ -H "Content-Type: application/json" \ -d '{"query": "{ resolveRoute(path: \"/\") { record { id } } }"}'

API Key Scopes

API keys can be configured with specific scopes to limit access:

ScopeDescription
entities:readRead entity records
entities:writeCreate and update entities
entities:deleteDelete entities
entities:publishPublish and unpublish entities
schemas:readRead project schemas
workflows:executeExecute workflows

Example: A read-only frontend key might have only entities:read scope.

Version Selection (Development Keys Only)

Development keys (pk_dev_) support version selection parameters:

versionState

query GetDraft { entity(modelKey: "page", id: "123", versionState: LATEST) { id data versionNumber } }
ValueDescription
ACTIVEPublished version (default)
LATESTLatest draft version
SPECIFICUse with versionId or versionNumber

Specific Version

# By version ID query GetSpecificVersion { entity(modelKey: "page", id: "123", versionId: "ver_456") { id data versionNumber } } # By version number query GetVersionByNumber { entity(modelKey: "page", id: "123", versionNumber: 5) { id data versionNumber } }

List Available Versions

query ListVersions { listEntityVersions(entityId: "123", limit: 10) { versions { id versionNumber state createdAt isActive isCurrentDraft } total } }

Security Best Practices

Environment Variables

Never hardcode API keys. Use environment variables:

// Next.js / Node.js const apiKey = process.env.FOIR_API_KEY; // Vite const apiKey = import.meta.env.VITE_FOIR_API_KEY;

Server-Side Only

Keep API keys on the server side when possible:

// Next.js App Router - Server Component async function getPageData(path: string) { const response = await fetch('https://api.foir.io/graphql/public', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': process.env.FOIR_API_KEY!, // Server-side only }, body: JSON.stringify({ query: RESOLVE_ROUTE_QUERY, variables: { path }, }), }); return response.json(); }

Client-Side Keys

If you must use API keys client-side:

  1. Use production keys only (read-only)
  2. Enable domain restrictions in API key settings
  3. Configure rate limiting per key
  4. Monitor usage in the admin dashboard

Key Rotation

Rotate API keys periodically:

  1. Create a new key with the same scopes
  2. Update your application to use the new key
  3. Verify the new key works
  4. Disable the old key
  5. Delete the old key after a grace period

Troubleshooting

”UNAUTHENTICATED” Error

{ "errors": [{ "message": "Authentication required", "extensions": { "code": "UNAUTHENTICATED" } }] }

Causes:

  • Missing x-api-key header
  • Invalid or expired API key
  • Key disabled in admin

”FORBIDDEN” Error

{ "errors": [{ "message": "Insufficient permissions", "extensions": { "code": "FORBIDDEN" } }] }

Causes:

  • API key lacks required scope
  • Domain restriction mismatch
  • Attempting to access other project’s data
Last updated on