Authentication & API Keys¶
Every 3PI partner authenticates using scoped API keys. Keys are designed for security-first integration with granular controls over what each key can access.
Key format¶
All 3PI partner keys use the vp3_ prefix for easy identification:
- Prefix:
vp3_— identifies this as a 3PI partner key - Length: 52 characters total (4-char prefix + 48 random characters)
- Storage: SHA-256 hashed at rest — Vellocity never stores the plaintext
Using your key¶
Include the key in the Authorization header as a Bearer token:
curl https://api.vell.ai/api/v1/3pi-partners \
-H "Authorization: Bearer vp3_YOUR_KEY_HERE" \
-H "Accept: application/json"
Never expose keys client-side
Partner API keys should only be used in server-to-server communication. Never embed them in frontend code, mobile apps, or any client-accessible location.
Creating keys¶
Each partner can have multiple API keys for different environments or services.
curl -X POST https://api.vell.ai/api/v1/3pi-partners/42/keys \
-H "Authorization: Bearer $ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Production - Content Service",
"scoped_capabilities": ["ai_writer", "content_studio", "marketplace_seo"],
"allowed_ip_addresses": ["203.0.113.10", "203.0.113.11"],
"rate_limit_per_minute": 120,
"daily_credit_limit": 5000,
"expires_at": "2027-03-15T00:00:00Z"
}'
Response:
{
"data": {
"id": 7,
"name": "Production - Content Service",
"prefix": "vp3_x9y8z7w6",
"scoped_capabilities": ["ai_writer", "content_studio", "marketplace_seo"],
"allowed_ip_addresses": ["203.0.113.10", "203.0.113.11"],
"rate_limit_per_minute": 120,
"daily_credit_limit": 5000,
"is_active": true,
"is_valid": true,
"expires_at": "2027-03-15T00:00:00Z",
"created_at": "2026-03-15T10:30:00Z"
},
"plaintext": "vp3_x9y8z7w6...",
"warning": "Store this key securely. It will not be shown again."
}
Key parameters¶
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Human-readable label for the key |
scoped_capabilities |
string[] | No | Restrict to specific capabilities. null = inherit all from partner |
allowed_ip_addresses |
string[] | No | IP allowlist. null = allow all IPs |
rate_limit_per_minute |
integer | No | Max requests per minute (default: 60, max: 10,000) |
daily_credit_limit |
integer | No | Max credits per day. null = unlimited |
expires_at |
datetime | No | Auto-expire date. null = no expiration |
Capability scoping¶
Keys can be restricted to specific capabilities. When scoped_capabilities is null, the key inherits all capabilities assigned to the partner.
If a request targets a capability not in the key's scope, the API returns 403 Forbidden:
{
"success": false,
"error": {
"code": "CAPABILITY_NOT_ALLOWED",
"message": "This API key does not have access to the 'partner_central' capability"
}
}
See Capabilities Reference for the full list of capability slugs.
IP allowlisting¶
Restrict key usage to specific IP addresses for defense-in-depth:
Requests from non-listed IPs receive 403 Forbidden. Set to null to allow any IP.
Rate limits¶
Each key has an independent rate limit:
| Parameter | Default | Max |
|---|---|---|
rate_limit_per_minute |
60 | 10,000 |
When rate limited, the API returns 429 Too Many Requests with retry headers:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1710500460
Retry-After: 15
Daily credit limits¶
Set a daily credit cap to control spend:
When the limit is reached, subsequent requests return 429 with:
{
"success": false,
"error": {
"code": "DAILY_CREDIT_LIMIT_EXCEEDED",
"message": "This API key has consumed 5000/5000 credits today. Limit resets at midnight UTC."
}
}
Sandbox requests don't count
Credit limits only apply to production requests. Sandbox mode requests always succeed regardless of limits.
Key rotation¶
Rotate a key to generate a new one with identical settings while revoking the old key:
curl -X POST https://api.vell.ai/api/v1/3pi-partners/42/keys/7/rotate \
-H "Authorization: Bearer $ADMIN_API_KEY"
Response:
{
"data": {
"id": 8,
"name": "Production - Content Service",
"prefix": "vp3_n3w0k3y1",
"scoped_capabilities": ["ai_writer", "content_studio", "marketplace_seo"],
"rate_limit_per_minute": 120,
"is_active": true,
"created_at": "2026-03-15T14:00:00Z"
},
"plaintext": "vp3_n3w0k3y1...",
"warning": "Store this key securely. It will not be shown again.",
"revoked_key_id": 7
}
The old key is immediately revoked. Plan for a brief switchover window in your deployment.
Key revocation¶
Revoke a key to permanently disable it:
curl -X POST https://api.vell.ai/api/v1/3pi-partners/42/keys/7/revoke \
-H "Authorization: Bearer $ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"reason": "Compromised key"}'
Revoked keys cannot be re-activated. Create a new key instead.
Listing keys¶
View all keys for a partner:
Response:
{
"data": [
{
"id": 8,
"name": "Production - Content Service",
"prefix": "vp3_n3w0k3y1",
"is_active": true,
"is_valid": true,
"total_requests": 1247,
"last_used_at": "2026-03-15T13:45:00Z",
"created_at": "2026-03-15T14:00:00Z"
},
{
"id": 7,
"name": "Production - Content Service",
"prefix": "vp3_x9y8z7w6",
"is_active": false,
"is_valid": false,
"revoked_at": "2026-03-15T14:00:00Z",
"revoked_reason": "Key rotation",
"total_requests": 8432,
"created_at": "2026-03-15T10:30:00Z"
}
]
}
Security best practices¶
- Use capability scoping — Only grant the capabilities each key needs
- Set IP allowlists — Restrict keys to known server IPs
- Set expiration dates — Auto-expire keys on a regular rotation schedule
- Use daily credit limits — Cap spend per key to limit blast radius
- Rotate regularly — Use the
/rotateendpoint for zero-downtime key rotation - Monitor usage — Review the Usage & Billing dashboard for anomalies
- One key per service — Issue separate keys for each service or environment
- Never log plaintext keys — The key hash, prefix, and ID are sufficient for debugging