Skip to main content
Developer Documentation

Documentation

Complete API reference, CLI commands, SDKs, and integration guides. Get started in 5 minutes.

Getting Started

Prerequisites

Docker 24+

For containerised install

Python 3.10+

For SDK / CLI

Node 18+

For JS/TS SDK

Install

bash
docker pull g8kepr/api:latest
docker run -d \
  -e API_KEY=your_api_key \
  -e DATABASE_URL=postgresql://user:pass@db:5432/g8kepr \
  -p 8000:8000 \
  --name g8kepr \
  g8kepr/api:latest
Docker pull & start
$docker pull g8kepr/api:latest
latest: Pulling from g8kepr/api
Digest: sha256:abc123...
Status: Downloaded newer image for g8kepr/api:latest
$docker run -d -p 8000:8000 g8kepr/api:latest
f3a1b2c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2
$

API key security

Your API key is shown once at creation. Store it immediately in your secrets manager — it cannot be retrieved again. Rotate keys from Dashboard → API Keys.

First Request

First request — curlbash
curl -X POST https://api.g8kepr.com/v1/gateway/completions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "messages": [{ "role": "user", "content": "Hello from G8KEPR!" }]
  }'
Responsejson
{
  "id": "chatcmpl-abc123",
  "object": "chat.completion",
  "model": "gpt-4o-mini",
  "choices": [{ "message": { "role": "assistant", "content": "Hello! How can I help?" } }],
  "g8kepr": {
    "threat_score": 0.01,
    "latency_ms": 312,
    "gateway_id": "gw_prod_01"
  }
}

SDK Setup

main.pypython
from g8kepr import G8KPRClient

client = G8KPRClient(api_key="YOUR_API_KEY")

response = client.gateway.complete(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Explain zero-trust security"}],
)
print(response.choices[0].message.content)

Architecture Overview

System Overview

G8KEPR Architecture Overview

Web Apps
Mobile
AI Agents
APIs
G8KEPR
API Security

OWASP Top 10

MCP Security

AI Tool Control

AI Gateway

Multi-LLM Routing

Observability

Metrics & Logs

Your APIs
Databases
LLM Providers

Request Flow

Request Flow Through G8KEPR

Client
G8KEPRInspect & Protect
Your API
1Rate Limiting
2Threat Detection
3Auth Validation
4Forward Request

Processing Layers

01

Ingress

TLS termination, IP allowlist, SNI routing

02

Gateway Proxy

Rate limiting, auth validation, idempotency

03

Threat Engine

1,500+ patterns, session correlation, ML scoring

04

Backend Forward

mTLS, retry, circuit-breaker, audit log

Deployment Options

Single Node

Development & small teams. Docker Compose, 1 server.

< 10k req/dayDocker

Patroni HA

Production HA with automatic failover. PostgreSQL primary + 2 replicas.

< 10M req/dayHA

Kubernetes

Enterprise scale. Helm chart, HPA, PodDisruptionBudget, zone-aware scheduling.

UnlimitedK8sMulti-region

Docker Compose

Docker Deployment Architecture

Docker Host
g8kepr-gateway
Image:g8kepr/gateway:latest
Port:8080:8080
CPU:500m
Memory:512Mi
redis
Image:redis:7-alpine
Port:6379
Volume:redis-data
Memory:256Mi
your-api
Image:your-app:latest
Port:3000
Depends:g8kepr-gateway
Network:g8kepr-net
Internet
:8080
:3000

Kubernetes / Helm

Kubernetes Deployment

Kubernetes Cluster
namespace: g8kepr
Ingressnginx-ingress
Serviceg8kepr-svc
Deploymentreplicas: 3
HPA3-10 pods
3Replicas
500mCPU/pod
512MiMemory/pod
99.9%SLA

API Security

Live Request Monitor

Live Request Monitor
1,247 req/min99.2% allowed0.8% blocked
GET/api/users20012ms✓ Clean
POST/api/orders20145ms✓ Clean
GET/api/users?id=1 OR 1=14032msSQL Injection
PUT/api/products/12320038ms✓ Clean
POST/api/login4291msRate Limited
GET/api/health2005ms✓ Clean

HTTP Integration

Direct HTTP Integration

REST API
api.g8kepr.com/v1
Any HTTP client
Bearer token auth
JSON responses
AI Gateway
OpenAI-compatible
Drop-in replacement
Use existing SDKs
No code changes
CLI Tool
pip install g8kepr-cli
Full API access
Automation ready
CI/CD friendly

OWASP Top 10 Coverage

A01

Broken Access Control

FULL
A02

Cryptographic Failures

FULL
A03

Injection

FULL
A04

Insecure Design

PARTIAL
A05

Security Misconfiguration

FULL
A06

Vulnerable Components

PARTIAL
A07

Auth & Identity Failures

FULL
A08

Data Integrity Failures

FULL
A09

Security Logging Failures

FULL
A10

SSRF

FULL

Rate Limiting Tiers

PlanReq / minReq / dayBurstConcurrent
Free6010,000105
Pro1,000500,00020050
EnterpriseUnlimitedUnlimited5,000Unlimited

Geo-Blocking Config

geo-blocking rulejson
{
  "rule_name": "block-high-risk-countries",
  "action": "block",
  "countries": ["CN", "RU", "KP", "IR"],
  "response_code": 403,
  "log": true
}

Rate limit headers

Always return rate limit headers are included in every response: X-RateLimit-Limit, X-RateLimit-Remaining, and Retry-After on 429. Implement exponential backoff — start at 1s, double each retry, cap at 32s.

MCP Security

MCP Security Flow

AI AgentClaude, GPT, etc.
Policy Engine
Allow
Review
Block
MCP Tools

Session Tracking

Include X-Session-ID in every request to enable multi-turn threat correlation. G8KEPR tracks escalation patterns across requests within a session.

bash
# All requests in a session share the same X-Session-ID
curl -X POST https://api.g8kepr.com/v1/gateway/completions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "X-Session-ID: sess_abc123xyz" \
  -H "Content-Type: application/json" \
  -d '{ "model": "gpt-4o", "messages": [...] }'

Tool Authorization — RBAC

Tool Categoryvieweroperatoradminsuper_admin
Read files
Write files
Execute code
Network access
System calls

Explainability Response

Threat analysis responsejson
{
  "allowed": false,
  "threat_score": 0.87,
  "decision": "block",
  "explanation": "Prompt injection pattern detected: role confusion + instruction override",
  "patterns_matched": [
    { "id": "PI-001", "name": "Role Confusion", "confidence": 0.92 },
    { "id": "PI-007", "name": "Instruction Override", "confidence": 0.81 }
  ],
  "session_escalation_factor": 2.0,
  "session_request_count": 4
}

Audit Log Query

bash
curl https://api.g8kepr.com/v1/mcp/audit?session_id=sess_abc123xyz \
  -H "Authorization: Bearer YOUR_API_KEY"

Session expiry

MCP sessions auto-expire after 30 minutes of inactivity. Extend via a heartbeat request to /v1/mcp/sessions/{id}/heartbeat — this resets the 30-minute clock without consuming quota.

AI Gateway

AI Gateway - Intelligent Routing

Your App
openai.chat()
AI Gateway
Cost Optimized
🟢OpenAI
🟣Anthropic
🔵Google
🟠Mistral
60%

Cost Savings

99.9%

Uptime

<50ms

Latency Added

Routing Strategies

Distributes requests evenly across all healthy providers. Good for load balancing when all providers have similar SLAs.

routing-rule.jsonjson
{
  "strategy": "round_robin",
  "providers": ["openai", "anthropic", "cohere"],
  "health_check_interval_s": 30
}

Model Marketplace

OpenAI

gpt-4o

gpt-4o-mini

o1

Anthropic

claude-opus-4-6

claude-sonnet-4-6

claude-haiku-4-5

Cohere

command-r-plus

command-r

embed-v3

Streaming

python
import httpx

with httpx.stream("POST", "https://api.g8kepr.com/v1/gateway/completions",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={"model": "gpt-4o", "messages": [...], "stream": True},
) as resp:
    for line in resp.iter_lines():
        if line.startswith("data: "):
            print(line[6:])  # SSE payload

Webhook Events

Webhook Event Flow

G8KEPREvent Triggered
POST /webhook
Your ServerProcess Event
threat.detected
request.blocked
rate_limit.exceeded
report.generated

Webhook Payload Schemas

All webhook payloads share a common envelope. Verify the signature using X-G8KEPR-Signature (HMAC-SHA256 of the raw body with your webhook secret).

threat.blocked— fired when a request is blocked by the threat engine
json
{
  "event": "threat.blocked",
  "version": "2.1",
  "timestamp": "2026-03-31T14:22:01.432Z",
  "org_id": "org_abc123",
  "gateway_id": "gw_prod_01",
  "data": {
    "request_id": "req_xyz789",
    "threat_score": 0.91,
    "decision": "block",
    "pattern_ids": ["PI-001", "PI-007"],
    "session_id": "sess_def456",
    "session_request_count": 4,
    "session_escalation_factor": 2.0,
    "source_ip": "1.2.3.4",
    "method": "POST",
    "path": "/v1/completions",
    "user_agent": "python-httpx/0.27.0"
  }
}
gateway.down— fired when a gateway health check fails
json
{
  "event": "gateway.down",
  "version": "2.1",
  "timestamp": "2026-03-31T14:30:00.001Z",
  "org_id": "org_abc123",
  "gateway_id": "gw_prod_01",
  "data": {
    "gateway_name": "Production",
    "backend_url": "https://api.example.com",
    "check_type": "http",
    "http_status": 503,
    "consecutive_failures": 3,
    "first_failure_at": "2026-03-31T14:29:00.000Z"
  }
}
rate_limit.exceeded— fired when an IP or key exceeds its limit
json
{
  "event": "rate_limit.exceeded",
  "version": "2.1",
  "timestamp": "2026-03-31T15:00:05.210Z",
  "org_id": "org_abc123",
  "gateway_id": "gw_prod_01",
  "data": {
    "scope": "per_ip",
    "identifier": "1.2.3.4",
    "limit": 100,
    "window_seconds": 60,
    "retry_after": 47
  }
}

Signature verification

Always verify X-G8KEPR-Signature before processing webhook payloads. Use hmac.compare_digest (Python) or crypto.timingSafeEqual (Node) to prevent timing attacks.

Threat Detection

Threat Detection Pipeline

Ingress

Request received

Pattern Match

1,500+ signatures

SQLi, XSS
ML Analysis

Behavioral detection

Anomalies
Policy Check

Rules evaluation

Rate limits
Decision

Allow / Block

SQL Injection
XSS
Path Traversal
Rate Limit
Auth Failure

1,500+

Threat patterns

15

Attack categories

<2ms

Avg analysis latency

Session Escalation Tiers

1 request

1.0×

Baseline score

3 requests

1.3×

Elevated threshold

5 requests

2.0×

High alert

8+ requests

2.5×

Auto-block

Live Threat Log

Threat detection events
$g8kepr threats stream --gateway gw_prod_01
Streaming threats for gateway gw_prod_01...
[2026-03-31T14:22:01Z] BLOCKED score=0.91 PI-001 Role Confusion ip=1.2.3.4
[2026-03-31T14:22:04Z] ALLOWED score=0.03 No patterns matched ip=5.6.7.8
[2026-03-31T14:22:09Z] BLOCKED score=0.78 PI-007 Instruction Override ip=1.2.3.5
[2026-03-31T14:22:15Z] ALERT score=0.64 Session escalation 2.0× ip=9.10.11.12
$

Response Policies

PolicyThresholdActionDescription
Log0.2 – 0.4Allow + logRecord event for analysis. No impact to request.
Alert0.4 – 0.6Allow + alertWebhook notification sent. Request continues.
Challenge0.6 – 0.7CAPTCHA / 2FAUser must verify before request is forwarded.
Block≥ 0.7HTTP 403Request rejected. Audit log written.

Auto-block threshold

Requests scoring ≥ 0.7 are blocked immediately — no queue, no retry. Tune the threshold via POST /v1/config/thresholds. Lowering it increases false-positive rate; raise it only after reviewing your threat logs.

CLI Reference

Installation

bash
brew tap g8kepr/tap
brew install g8kepr
g8kepr --version
# g8kepr v2.1.0

Authentication

bash
# Login with browser OAuth
g8kepr login

# Or supply API key directly
g8kepr login --api-key YOUR_API_KEY

# Verify auth status
g8kepr auth status
# Logged in as: wesley@example.com (org: acme-corp)

Command Reference

CommandFlagsDescription
g8kepr login--api-key, --orgAuthenticate with G8KEPR
g8kepr auth statusShow current auth context
g8kepr gateway list--json, --orgList all gateways
g8kepr gateway create--name, --backend-urlCreate a new gateway
g8kepr gateway delete--id, --forceDelete a gateway
g8kepr threats stream--gateway, --sinceStream live threat events
g8kepr threats export--start, --end, --formatExport threat log to CSV/JSON
g8kepr rules add--type, --configAdd rate-limit or geo-blocking rule
g8kepr rules list--gateway, --typeList active rules
g8kepr rules delete--idDelete a rule
g8kepr config set--key, --valueUpdate a config value
g8kepr config show--jsonShow current configuration
g8kepr health--verboseCheck platform health
g8kepr logs--gateway, --levelTail platform logs
g8kepr api-keys list--orgList API keys for org
g8kepr gateway list --json
$g8kepr gateway list --json
[
{ "id": "gw_prod_01", "name": "Production", "backend": "api.example.com", "status": "healthy", "req_today": 142891 },
{ "id": "gw_staging_01", "name": "Staging", "backend": "staging.example.com", "status": "healthy", "req_today": 3211 }
]
$

Machine-readable output

All commands support --json for machine-readable output. Pipe to jq in CI: g8kepr threats export --format json | jq '.[] | select(.score > 0.7)'

API Reference

API Key Authentication Flow

Your App
1. Send KeyAuthorization: Bearer
G8KEPRValidate & Authorize
3. Check Permsscopes, limits
Your API
g8k_live_*Production - Full access
g8k_test_*Sandbox - No billing
g8k_rstr_*Restricted - Limited
Base URLhttps://api.g8kepr.com/v1

Authentication

bash
# All requests require Bearer token
curl https://api.g8kepr.com/v1/gateways \
  -H "Authorization: Bearer YOUR_API_KEY"

# Rotate a key (old key remains valid for 15 min)
curl -X POST https://api.g8kepr.com/v1/api-keys/rotate \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{ "key_id": "key_abc123" }'

Endpoints

Rate Limit Response Headers

HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the current window
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when the window resets
Retry-AfterSeconds to wait before retrying (on 429 only)

Error codes

400 Bad Request — invalid body or missing required field. 401 Unauthorized — missing or expired API key. 403 Forbidden — insufficient permissions or blocked by policy. 429 Too Many Requests — check Retry-After header. 503 Service Unavailable — Redis or DB health check failed; retry with backoff.

Configuration

Configuration File Structure

g8kepr.yaml
tenant:your-tenant
protection:standard
rate_limit:1000/min
alerts:enabled
.env
G8KEPR_API_KEY=g8k_live_***
G8KEPR_API_URL=https://api.g8kepr.com
G8KEPR_ORGANIZATION_ID=org_123
G8KEPR_OUTPUT_FORMAT=table

Compliance Frameworks

Compliance Framework Coverage

🔒
SOC 2
51/51 controls
🌐
ISO 27001
56/93 controls
🏥
HIPAA
47/49 controls
💳
PCI DSS
24/312 controls
🏛️
NIST CSF
53/106 controls
🇪🇺
GDPR
22/22 controls

Environment Variables

VariableRequiredDefaultDescription
DATABASE_URLrequiredPostgreSQL connection string
REDIS_URLrequiredRedis connection string for rate limiting & sessions
SECRET_KEYrequired32+ char secret for JWT signing
API_ENCRYPTION_KEYrequiredFernet key for encrypting stored API keys
ENVIRONMENToptionalproductionproduction | staging | development
LOG_LEVELoptionalinfodebug | info | warning | error
OPENAI_API_KEYoptionalRequired to use OpenAI via AI Gateway
ANTHROPIC_API_KEYoptionalRequired to use Anthropic via AI Gateway
SENTRY_DSNoptionalError monitoring (recommended for production)
POSTHOG_API_KEYoptionalAnalytics (PII-safe — no user content logged)
ALLOWED_ORIGINSoptional*Comma-separated CORS allowed origins
WORKERSoptional4Uvicorn worker count (set to CPU cores × 2)

Docker Compose — env injection

docker-compose.prod.yml (excerpt)yaml
services:
  backend:
    image: g8kepr/api:2.1.0
    environment:
      DATABASE_URL: ${DATABASE_URL}
      REDIS_URL: ${REDIS_URL}
      SECRET_KEY: ${SECRET_KEY}
      API_ENCRYPTION_KEY: ${API_ENCRYPTION_KEY}
      ENVIRONMENT: production
      LOG_LEVEL: info
      WORKERS: 4
    env_file:
      - .env.production  # blocked from git by pre-commit hook

Feature Flags

FlagDefaultEffect when enabled
FEATURE_MCP_SECURITYtrueEnable MCP Security pillar and session tracking
FEATURE_AI_GATEWAYtrueEnable AI Gateway routing and marketplace
FEATURE_GEO_BLOCKINGfalseEnable geo-blocking rules UI and enforcement
FEATURE_HIPAA_BAAfalseShow HIPAA BAA module (requires enterprise plan)
FEATURE_SOC2_REPORTSfalseEnable SOC 2 compliance reporting tab

Secrets management

.env.production commits are blocked by the pre-commit hook. Use your cloud provider's secrets manager (AWS Secrets Manager, GCP Secret Manager, Vault) and inject at runtime via env_file or environment variable injection.

Troubleshooting

Common Errors

Debug Mode

bash
# Enable verbose logging
LOG_LEVEL=debug g8kepr serve

# Or set in environment
export LOG_LEVEL=debug
docker compose up backend

Health Check Endpoints

EndpointChecksUse case
GET /healthProcess aliveLoad balancer liveness probe
GET /health/dbPostgreSQL connectivity + queryReadiness probe, alerting
GET /health/redisRedis PING + latencyReadiness probe, alerting
GET /health/fullAll of the above + worker queueMonitoring dashboards

GitHub Issues

Bug reports, feature requests, and security disclosures.

Open an issue →

Enterprise Support

Priority support, SLA, and dedicated Slack channel for Enterprise plans.

Contact sales →

Monitoring & Observability

G8KEPR ships with a full observability stack: Prometheus metrics, pre-built Grafana dashboards, and structured JSON logs compatible with any aggregator (Loki, Datadog, ELK).

Prometheus Metrics

Metrics are exposed at GET /metrics in Prometheus text format. Scrape interval recommended: 15s.

MetricTypeDescription
g8kepr_requests_totalCounterTotal requests proxied, labeled by gateway, method, status
g8kepr_request_duration_secondsHistogramEnd-to-end request latency (p50/p95/p99 available)
g8kepr_threats_totalCounterThreats detected, labeled by decision (block/alert/log)
g8kepr_threat_scoreHistogramDistribution of threat scores across all requests
g8kepr_rate_limit_hits_totalCounterRate limit 429 responses, labeled by scope and gateway
g8kepr_session_escalations_totalCounterMulti-turn session escalation events by tier
g8kepr_gateway_healthGauge1=healthy 0=unhealthy, labeled by gateway_id
g8kepr_db_pool_sizeGaugeActive / idle PostgreSQL connections
g8kepr_redis_latency_secondsHistogramRedis command latency
g8kepr_ai_tokens_totalCounterLLM tokens consumed via AI Gateway, labeled by model and provider

Prometheus Scrape Config

prometheus.ymlyaml
scrape_configs:
  - job_name: 'g8kepr'
    scrape_interval: 15s
    static_configs:
      - targets: ['g8kepr-backend:8000']
    metrics_path: /metrics
    bearer_token: YOUR_METRICS_TOKEN

Grafana Dashboard Setup

Import the pre-built dashboards from the monitoring/grafana/dashboards/ directory in the repo. Three dashboards are included:

G8KEPR Overview

Request volume, threat rate, gateway health, p95 latency — the oncall dashboard

Threat Intelligence

Threat score distribution, top patterns, session escalations, geo heatmap

AI Gateway

Token consumption, cost by model/provider, routing distribution, error rates

bash
# Import via Grafana CLI
grafana-cli dashboards import monitoring/grafana/dashboards/overview.json
grafana-cli dashboards import monitoring/grafana/dashboards/threats.json
grafana-cli dashboards import monitoring/grafana/dashboards/ai-gateway.json

# Or via API
curl -X POST http://grafana:3000/api/dashboards/import \
  -H "Authorization: Basic admin:admin" \
  -H "Content-Type: application/json" \
  -d @monitoring/grafana/dashboards/overview.json

Alert Rules

AlertSeverityConditionDefault threshold
GatewayDowncriticalg8kepr_gateway_health == 0Immediate
HighThreatRatewarningrate(g8kepr_threats_total[5m]) > N> 50/min
HighLatencywarningp95 request duration> 2s for 5 min
ContainerRestartingcriticalrestart count delta> 3 in 15 min
RedisLatencyHighwarningg8kepr_redis_latency_seconds p99> 100ms
TokenBudgetNearingwarningdaily token spend vs limit> 80% of budget

Log Format

All logs are structured JSON, written to stdout. Each log line includes request_id for end-to-end tracing.

Sample log linejson
{
  "level": "info",
  "time": "2026-03-31T14:22:01.432Z",
  "request_id": "req_xyz789",
  "org_id": "org_abc123",
  "gateway_id": "gw_prod_01",
  "method": "POST",
  "path": "/v1/completions",
  "status": 403,
  "duration_ms": 4,
  "threat_score": 0.91,
  "decision": "block",
  "pattern": "PI-001"
}

Changelog

All notable changes to G8KEPR. We follow Semantic Versioning.

v2.1.0Latest2026-03-31
  • NewMCP Security pillar — session tracking, tool RBAC, explainability scoring
  • NewMulti-turn session correlation with 1.3× / 2.0× / 2.5× escalation tiers
  • NewIdempotency-Key middleware (Redis-backed, 24h TTL) on all write endpoints
  • ImprovedAPI Security raised to A+ — all 12 Core Standards satisfied
  • ImprovedRate limiter moved from in-process Map to nginx limit_req_zone (multi-worker safe)
  • FixedWebSocket IDOR — gateway authorization now runs before websocket.accept()
  • FixedGateway proxy fail-open on Redis error changed to 503 + Retry-After
v2.0.02026-03-15
  • NewAI Gateway pillar — multi-provider routing with 4 strategies (round-robin, least-latency, cost-optimized, failover)
  • NewModel marketplace supporting OpenAI, Anthropic, Cohere, Mistral, and Google
  • NewKubernetes Helm chart v1.0.0 with HPA, PodDisruptionBudget, and zone-aware scheduling
  • ImprovedAuth upgraded to A+ — full RBAC matrix, billing:manage permission, MFA for destructive ops
  • ImprovedMulti-tenant isolation verified: PostgreSQL RLS + app-layer org_id + Redis key-scoping
  • BreakingAPI v0 endpoints removed. Migrate to /v1/ — see migration guide below.
v1.9.02026-02-28
  • NewPatroni HA mode — automatic PostgreSQL failover with <30s RTO
  • NewPrometheus metrics endpoint + 3 pre-built Grafana dashboards
  • NewWebhook system — threat.blocked, gateway.down, rate_limit.exceeded events
  • ImprovedDocker images fully pinned with SHA digests — no more :latest tag surprises
  • FixedBFF SQL injection on filter column names — now validated via allowlist
v1.8.02026-01-31
  • NewEU AI Act compliance module with Art. 9/12/13 evidence generation
  • NewSOC 2 Type I audit trail — tamper-evident audit log with 7-year retention
  • NewGeo-blocking rules with country-level allow/deny lists
  • ImprovedThreat detection patterns expanded from 682 → 1,500+ across 15 categories
  • ImprovedBackend test coverage raised from 0% → 31.70% (gate: 70%, module-scope: 52.65%)
Ready to secure your APIs?

Start protecting your APIs today

Free tier includes 10,000 requests/day, full threat detection, and all four security pillars. No credit card required.