POST
/
v2
/
keys.createKey
Go (SDK)
package main

import(
	"context"
	"os"
	unkey "github.com/unkeyed/sdks/api/go/v2"
	"github.com/unkeyed/sdks/api/go/v2/models/components"
	"log"
)

func main() {
    ctx := context.Background()

    s := unkey.New(
        unkey.WithSecurity(os.Getenv("UNKEY_ROOT_KEY")),
    )

    res, err := s.Keys.CreateKey(ctx, components.V2KeysCreateKeyRequestBody{
        APIID: "api_1234abcd",
        Prefix: unkey.String("prod"),
        Name: unkey.String("Payment Service Production Key"),
        ByteLength: unkey.Int64(24),
        ExternalID: unkey.String("user_1234abcd"),
        Meta: map[string]any{
            "plan": "enterprise",
            "featureFlags": map[string]any{
                "betaAccess": true,
                "concurrentConnections": 10,
            },
            "customerName": "Acme Corp",
            "billing": map[string]any{
                "tier": "premium",
                "renewal": "2024-12-31",
            },
        },
        Roles: []string{
            "api_admin",
            "billing_reader",
        },
        Permissions: []string{
            "documents.read",
            "documents.write",
            "settings.view",
        },
        Expires: unkey.Int64(1704067200000),
        Credits: &components.KeyCreditsData{
            Remaining: unkey.Int64(1000),
            Refill: &components.KeyCreditsRefill{
                Interval: components.KeyCreditsRefillIntervalDaily,
                Amount: 1000,
                RefillDay: unkey.Int64(15),
            },
        },
        Ratelimits: []components.RatelimitRequest{
            components.RatelimitRequest{
                Name: "requests",
                Limit: 100,
                Duration: 60000,
                AutoApply: unkey.Bool(true),
            },
            components.RatelimitRequest{
                Name: "heavy_operations",
                Limit: 10,
                Duration: 3600000,
            },
        },
    })
    if err != nil {
        log.Fatal(err)
    }
    if res.V2KeysCreateKeyResponseBody != nil {
        // handle response
    }
}
{
  "meta": {
    "requestId": "req_123"
  },
  "data": {
    "keyId": "key_2cGKbMxRyIzhCxo1Idjz8q",
    "key": "prod_2cGKbMxRjIzhCxo1IdjH3arELti7Sdyc8w6XYbvtcyuBowPT"
  }
}

Authorizations

Authorization
string
header
required

Unkey uses API keys (root keys) for authentication. These keys authorize access to management operations in the API. To authenticate, include your root key in the Authorization header of each request:

Authorization: Bearer unkey_123

Root keys have specific permissions attached to them, controlling what operations they can perform. Key permissions follow a hierarchical structure with patterns like resource.resource_id.action (e.g., apis.*.create_key, apis.*.read_api). Security best practices:

  • Keep root keys secure and never expose them in client-side code
  • Use different root keys for different environments
  • Rotate keys periodically, especially after team member departures
  • Create keys with minimal necessary permissions following least privilege principle
  • Monitor key usage with audit logs.

Body

application/json
apiId
string
required

The API namespace this key belongs to. Keys from different APIs cannot access each other.

Required string length: 3 - 255
Example:

"api_1234abcd"

prefix
string

Adds a visual identifier to the beginning of the generated key for easier recognition in logs and dashboards. The prefix becomes part of the actual key string (e.g., prod_xxxxxxxxx). Avoid using sensitive information in prefixes as they may appear in logs and error messages.

Required string length: 1 - 16
Example:

"prod"

name
string

Sets a human-readable identifier for internal organization and dashboard display. Never exposed to end users, only visible in management interfaces and API responses. Avoid generic names like "API Key" when managing multiple keys for the same user or service.

Required string length: 1 - 200
Example:

"Payment Service Production Key"

byteLength
integer
default:16

Controls the cryptographic strength of the generated key in bytes. Higher values increase security but result in longer keys that may be more annoying to handle. The default 16 bytes provides 2^128 possible combinations, sufficient for most applications. Consider 32 bytes for highly sensitive APIs, but avoid values above 64 bytes unless specifically required.

Required range: 16 <= x <= 255
Example:

24

externalId
string

Links this key to a user or entity in your system using your own identifier. Returned during verification to identify the key owner without additional database lookups. Essential for user-specific analytics, billing, and multi-tenant key management. Use your primary user ID, organization ID, or tenant ID for best results. Accepts letters, numbers, underscores, dots, and hyphens for flexible identifier formats.

Required string length: 1 - 255
Example:

"user_1234abcd"

meta
object

Stores arbitrary JSON metadata returned during key verification for contextual information. Eliminates additional database lookups during verification, improving performance for stateless services. Avoid storing sensitive data here as it's returned in verification responses. Large metadata objects increase verification latency and should stay under 10KB total size.

Example:
{
"plan": "enterprise",
"featureFlags": {
"betaAccess": true,
"concurrentConnections": 10
},
"customerName": "Acme Corp",
"billing": {
"tier": "premium",
"renewal": "2024-12-31"
}
}
roles
string[]

Assigns existing roles to this key for permission management through role-based access control. Roles must already exist in your workspace before assignment. During verification, all permissions from assigned roles are checked against requested permissions. Roles provide a convenient way to group permissions and apply consistent access patterns across multiple keys.

Maximum length: 100
Example:
["api_admin", "billing_reader"]
permissions
string[]

Grants specific permissions directly to this key without requiring role membership. Wildcard permissions like documents.* grant access to all sub-permissions including documents.read and documents.write. Direct permissions supplement any permissions inherited from assigned roles.

Maximum length: 1000
Example:
[
"documents.read",
"documents.write",
"settings.view"
]
expires
integer

Sets when this key automatically expires as a Unix timestamp in milliseconds. Verification fails with code=EXPIRED immediately after this time passes. Omitting this field creates a permanent key that never expires.

Avoid setting timestamps in the past as they immediately invalidate the key. Keys expire based on server time, not client time, which prevents timezone-related issues. Essential for trial periods, temporary access, and security compliance requiring key rotation.

Required range: 0 <= x <= 4102444800000
Example:

1704067200000

credits
object

Controls usage-based limits through credit consumption with optional automatic refills. Unlike rate limits which control frequency, credits control total usage with global consistency. Essential for implementing usage-based pricing, subscription tiers, and hard usage quotas. Omitting this field creates unlimited usage, while setting null is not allowed during creation.

ratelimits
object[]

Defines time-based rate limits that protect against abuse by controlling request frequency. Unlike credits which track total usage, rate limits reset automatically after each window expires. Multiple rate limits can control different operation types with separate thresholds and windows. Essential for preventing API abuse while maintaining good performance for legitimate usage.

Maximum length: 50
Example:
[
{
"name": "requests",
"limit": 100,
"duration": 60000,
"autoApply": true
},
{
"name": "heavy_operations",
"limit": 10,
"duration": 3600000,
"autoApply": false
}
]
enabled
boolean
default:true

Controls whether the key is active immediately upon creation. When set to false, the key exists but all verification attempts fail with code=DISABLED. Useful for pre-creating keys that will be activated later or for keys requiring manual approval. Most keys should be created with enabled=true for immediate use.

Example:

true

recoverable
boolean
default:false

Controls whether the plaintext key is stored in an encrypted vault for later retrieval. When true, allows recovering the actual key value using keys.getKey with decrypt=true. When false, the key value cannot be retrieved after creation for maximum security. Only enable for development keys or when key recovery is absolutely necessary.

Example:

false

Response

Successfully created a new API key. The response includes both the keyId (for reference in your system) and the full key string. IMPORTANT: This is the only time the complete key is available - it cannot be retrieved later. You must securely provide this key to your end user immediately.

meta
object
required

Metadata object included in every API response. This provides context about the request and is essential for debugging, audit trails, and support inquiries. The requestId is particularly important when troubleshooting issues with the Unkey support team.

data
object
required