Create an API key
const url = 'https://api.pixonaut.app/v1/api-keys';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"allowedOrigins":["https://shop.acme.example"],"kind":"pk","label":"Storefront widget"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.pixonaut.app/v1/api-keys \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "allowedOrigins": [ "https://shop.acme.example" ], "kind": "pk", "label": "Storefront widget" }'Operation ID: apiKeys.create
Answers with the key itself, which is never shown again. A publishable key is refused from any origin outside its allowedOrigins. An MCP key is created by a member, for their own AI assistant, and acts as them; in a sandbox it acts on the sandbox alone.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”Responses
Section titled “Responses”The new key
object
The key itself. Shown in this response only.
Where an AI assistant reaches Pixel’s tools with an MCP key: this API’s own MCP address. Null for any other kind.
Examples
Example
{ "allowedOrigins": [ "https://shop.acme.example" ], "createdAt": 1760000000000, "expiresAt": null, "id": "3b2d9c1e-5a4f-4e7d-8c6b-1a0f9e8d7c6b", "key": "pk_live_0123456789abcdef01234567", "kind": "pk", "label": "Storefront widget", "mcpServer": null}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Refused: invalid_origin, origins_not_allowed, expiry_not_allowed, invalid_input
object
Always sent with invalid_origin.
Examples
expiry_not_allowed
{ "error": "expiry_not_allowed"}invalid_input
{ "error": "invalid_input"}invalid_origin
{ "error": "invalid_origin", "origin": "string"}origins_not_allowed
{ "error": "origins_not_allowed"}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Refused: unauthorized
object
Examples
unauthorized
{ "error": "unauthorized"}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Refused: forbidden, feature_disabled, plan_limit_reached, origin_forbidden
object
The feature the tenant does not have. Always sent with feature_disabled.
The limit the tenant is at: templates, connectedStores, apiKeys, shareLinks, customDomains, printsMadePerMonth (prints made without an order this month), members, orders (this month’s orders, which getting a print’s files without an order counts as), or a sandbox’s own caps: sandboxPrintsPerDay, sandboxPrintsPerMonth, sandboxOrdersPerMonth. A sandbox shares every other limit with its live workspace. Always sent with plan_limit_reached.
How many the plan allows. Always sent with plan_limit_reached.
The plan whose limit it is. Always sent with plan_limit_reached.
Examples
feature_disabled
{ "error": "feature_disabled", "feature": "api"}forbidden
{ "error": "forbidden"}origin_forbidden
{ "error": "origin_forbidden"}plan_limit_reached
{ "error": "plan_limit_reached", "limit": "templates", "max": 0, "plan": "free"}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Refused: payload_too_large
object
Always sent with payload_too_large.
Examples
payload_too_large
{ "error": "payload_too_large", "maxBytes": 0}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Refused: rate_limited
object
Examples
rate_limited
{ "error": "rate_limited"}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Refused: db_error. A request that failed unexpectedly answers as text instead.
object
Examples
db_error
{ "error": "db_error"}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Refused: lock_timeout
object
Examples
lock_timeout
{ "error": "lock_timeout"}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Questions? Write to [email protected].