{"openapi":"3.1.0","info":{"title":"Management API","version":"1.0.0"},"paths":{"/v1/keys":{"get":{"operationId":"keys_list","summary":"List API keys","description":"Return the organization's API keys with their current usage, wrapped in a list envelope. The management key's organization is implied by the key itself. A page holds at most 100 keys; when has_more is true, advance offset to read the rest.","tags":["keys"],"parameters":[{"name":"offset","in":"query","description":"Number of keys to skip.","required":false,"schema":{"type":"integer","minimum":0,"default":0}},{"name":"limit","in":"query","description":"Maximum number of keys to return (max 100).","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":100}}],"responses":{"200":{"description":"A page of the organization's keys.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyList"}}}},"401":{"description":"Missing or invalid management key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"ManagementKey":[]}]},"post":{"operationId":"keys_create","summary":"Create an API key","description":"Mint a new API key. The raw key is returned exactly once in the `key` field. Pass an optional `limit` and `limit_reset` to attach a spend cap.","tags":["keys"],"responses":{"201":{"description":"The created key, including the raw secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyCreated"}}}},"400":{"description":"Invalid request, for example an unsupported `limit_reset`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid management key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyRequest"}}}},"security":[{"ManagementKey":[]}]}},"/v1/keys/{key_hash}":{"get":{"operationId":"keys_get","summary":"Get an API key","description":"Return a single key with its current usage.","tags":["keys"],"parameters":[{"name":"key_hash","in":"path","description":"The key's `hash` from a create or list response.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Key"}}}},"401":{"description":"Missing or invalid management key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Key not found in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"ManagementKey":[]}]},"delete":{"operationId":"keys_delete","summary":"Delete an API key","description":"Revoke a key immediately. Its historical spend is retained for reporting. To stop a key without losing it, set `disabled` instead.","tags":["keys"],"parameters":[{"name":"key_hash","in":"path","description":"The key's `hash` from a create or list response.","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"The key was deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Missing or invalid management key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Key not found in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"ManagementKey":[]}]},"patch":{"operationId":"keys_update","summary":"Update an API key","description":"Update a key's name, disabled state, or spend limit. Only the fields you send change.","tags":["keys"],"parameters":[{"name":"key_hash","in":"path","description":"The key's `hash` from a create or list response.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Key"}}}},"400":{"description":"Invalid request, for example an unsupported `limit_reset`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid management key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Key not found in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKeyRequest"}}}},"security":[{"ManagementKey":[]}]}},"/v1/projects":{"get":{"operationId":"listProjects","summary":"List projects","description":"Keyset-paginated list of the organization's projects, each with its routing and budget config. Requires the manage_projects scope.","parameters":[{"name":"cursor","in":"query","description":"Opaque cursor from a previous response's next field.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"The organization's projects.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectList"}}}}},"security":[{"ManagementKey":[]}]},"post":{"operationId":"createProject","summary":"Create a project","description":"Create a project, optionally with a project-scoped routing policy and a spending limit. Requires the manage_projects scope.","responses":{"201":{"description":"The created project.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"422":{"description":"Validation error (e.g. routing_policy missing when uses_organization_default_routing is false, or PRIORITY mixed with allowed_models).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}}},"security":[{"ManagementKey":[]}]}},"/v1/projects/{project_id}":{"get":{"operationId":"getProject","summary":"Get a project","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The project.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"404":{"description":"Project not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"ManagementKey":[]}]},"patch":{"operationId":"updateProject","summary":"Update a project","description":"Update fields you send. routing_policy fully replaces the scoped policy in place (stable id); uses_organization_default_routing=true deletes it.","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The updated project.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"404":{"description":"Project not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Contradictory routing fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectRequest"}}}},"security":[{"ManagementKey":[]}]},"delete":{"operationId":"deleteProject","summary":"Delete a project","description":"Deletes the project plus its scoped routing policy and budget. Blocked while active project-scoped API keys exist.","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"404":{"description":"Project not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"PROJECT_HAS_ACTIVE_API_KEYS: revoke the project's API keys first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"DATA_PLANE_UNAVAILABLE: could not verify the project's API keys; retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"ManagementKey":[]}]}},"/v1/projects/{project_id}/usage":{"get":{"operationId":"getProjectUsage","summary":"Get project usage","description":"Day-granular spend totals for one project, plus a month-granular per-model breakdown. Requires the read_usage scope.","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"start","in":"query","description":"YYYY-MM-DD, inclusive. Defaults to the start of the current month.","required":false,"schema":{"type":"string","format":"date"}},{"name":"end","in":"query","description":"YYYY-MM-DD, inclusive. Defaults to today.","required":false,"schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Project spend for the range.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectUsage"}}}},"400":{"description":"Invalid or reversed date range.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"ManagementKey":[]}]}},"/v1/projects/{project_id}/pi-settings":{"get":{"operationId":"getProjectPiSettings","summary":"Get a project's prompt injection settings","description":"Returns the project's override, the effective policy after merging with the organization's, and which fields are inherited. A project pinned to an API key uses this policy as written. A project named per request (project_id body field or X-Project-Id header) may only tighten the organization policy; anything that loosens it is ignored at request time.","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The project's settings, with the effective policy resolved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectPiSettings"}}}},"403":{"description":"The management key lacks the manage_projects scope, or the feature is not enabled for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project not found, or it belongs to another organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"ManagementKey":[]}]},"put":{"operationId":"updateProjectPiSettings","summary":"Replace a project's prompt injection settings","description":"Replaces the override as a whole. Fields you omit inherit the organization value; send a field as null to clear it back to inheritance. An empty body means inherit everything, the same as DELETE. A project pinned to an API key uses this policy as written. A project named per request (project_id body field or X-Project-Id header) may only tighten the organization policy; anything that loosens it is ignored at request time.","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The project's settings, with the effective policy resolved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectPiSettings"}}}},"403":{"description":"The management key lacks the manage_projects scope, or the feature is not enabled for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project not found, or it belongs to another organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid field, unknown field, or an override the organization policy cannot support (for example a block threshold below the org's pass threshold).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PiProtectionOverride"}}}},"security":[{"ManagementKey":[]}]},"delete":{"operationId":"deleteProjectPiSettings","summary":"Delete a project's prompt injection settings","description":"Clears the override so the project inherits the organization policy as a whole.","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The project's settings, with the effective policy resolved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectPiSettings"}}}},"403":{"description":"The management key lacks the manage_projects scope, or the feature is not enabled for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project not found, or it belongs to another organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"ManagementKey":[]}]}},"/v1/projects/{project_id}/dlp-settings":{"get":{"operationId":"getProjectDlpSettings","summary":"Get a project's DLP settings","description":"Returns the project's override keyed by entity type, plus how every entity in the organization's catalog resolves for this project. A project pinned to an API key uses this policy as written. A project named per request (project_id body field or X-Project-Id header) may only tighten the organization policy; anything that loosens it is ignored at request time.","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The project's settings, with the effective policy resolved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDlpSettings"}}}},"403":{"description":"The management key lacks the manage_projects scope, or the feature is not enabled for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project not found, or it belongs to another organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"ManagementKey":[]}]},"put":{"operationId":"updateProjectDlpSettings","summary":"Replace a project's DLP settings","description":"Replaces the override as a whole. Entity types you omit inherit the organization's rule; an empty override map means inherit everything, the same as DELETE. A project pinned to an API key uses this policy as written. A project named per request (project_id body field or X-Project-Id header) may only tighten the organization policy; anything that loosens it is ignored at request time.","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The project's settings, with the effective policy resolved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDlpSettings"}}}},"403":{"description":"The management key lacks the manage_projects scope, or the feature is not enabled for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project not found, or it belongs to another organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Unknown entity type, invalid action, or a write past the per-organization override limits.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDlpOverrideRequest"}}}},"security":[{"ManagementKey":[]}]},"delete":{"operationId":"deleteProjectDlpSettings","summary":"Delete a project's DLP settings","description":"Clears the override so the project inherits the organization's DLP rules as a whole.","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The project's settings, with the effective policy resolved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDlpSettings"}}}},"403":{"description":"The management key lacks the manage_projects scope, or the feature is not enabled for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project not found, or it belongs to another organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"ManagementKey":[]}]}},"/v1/routing-policies":{"get":{"operationId":"listRoutingPolicies","summary":"List routing policies","description":"List the organization's standalone routing policies. Customer-, project-scoped, and derived policies are excluded. Requires the manage_routing scope.\n\nAuthenticates with a management key (manage_routing scope) or any active gateway API key of the organization.","responses":{"200":{"description":"The org's routing policies.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgRoutingPolicyList"}}}}},"security":[{"ManagementKey":[]}]},"post":{"operationId":"createRoutingPolicy","summary":"Create a routing policy","description":"Create an org routing policy. The first policy becomes the org default automatically. Requires the manage_routing scope.\n\nAuthenticates with a management key (manage_routing scope) or any active gateway API key of the organization.","responses":{"201":{"description":"The created policy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoutingPolicy"}}}},"422":{"description":"Validation error (e.g. PRIORITY mixed with allowed_models).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgRoutingPolicyCreate"}}}},"security":[{"ManagementKey":[]}]}},"/v1/routing-policies/{policy_id}":{"get":{"operationId":"getRoutingPolicy","summary":"Get a routing policy","description":"Authenticates with a management key (manage_routing scope) or any active gateway API key of the organization.","parameters":[{"name":"policy_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The policy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoutingPolicy"}}}},"404":{"description":"Not found (or not an org-level policy).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"ManagementKey":[]}]},"patch":{"operationId":"updateRoutingPolicy","summary":"Update a routing policy","description":"Update in place; the policy id is stable across updates.\n\nAuthenticates with a management key (manage_routing scope) or any active gateway API key of the organization.","parameters":[{"name":"policy_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The updated policy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoutingPolicy"}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid strategy fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgRoutingPolicyUpdate"}}}},"security":[{"ManagementKey":[]}]},"delete":{"operationId":"deleteRoutingPolicy","summary":"Delete a routing policy","description":"Deleting the default leaves the org with no default until another is set.\n\nAuthenticates with a management key (manage_routing scope) or any active gateway API key of the organization.","parameters":[{"name":"policy_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"ManagementKey":[]}]}},"/v1/routing-policies/{policy_id}/set-default":{"post":{"operationId":"setDefaultRoutingPolicy","summary":"Set the org default policy","description":"Make this policy the org default (unsets the previous default). Requires the manage_routing scope.\n\nAuthenticates with a management key (manage_routing scope) or any active gateway API key of the organization.","parameters":[{"name":"policy_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The policy, now default.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoutingPolicy"}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"ManagementKey":[]}]}},"/v1/organization/usage":{"get":{"operationId":"getOrganizationUsage","summary":"Get organization usage","description":"Organization-wide spend rollup: day-granular totals, month-granular per-model breakdown, and optional per-project / per-key / per-vendor grouping. Requires the read_usage scope.","parameters":[{"name":"start","in":"query","description":"YYYY-MM-DD, inclusive. Defaults to the start of the current month.","required":false,"schema":{"type":"string","format":"date"}},{"name":"end","in":"query","description":"YYYY-MM-DD, inclusive. Defaults to today.","required":false,"schema":{"type":"string","format":"date"}},{"name":"group_by","in":"query","required":false,"schema":{"$ref":"#/components/schemas/V1OrganizationUsageGetParametersGroupBy"}}],"responses":{"200":{"description":"Organization spend for the range.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationUsage"}}}},"400":{"description":"Invalid or reversed date range.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"ManagementKey":[]}]}}},"tags":[{"name":"keys"}],"servers":[{"url":"https://api-gateway.merge.dev","description":"https://api-gateway.merge.dev"}],"components":{"schemas":{"KeyLimitReset":{"type":"string","enum":["daily","weekly","monthly"],"description":"Window the spend cap resets on. Resets at midnight UTC.","title":"KeyLimitReset"},"Key":{"type":"object","properties":{"hash":{"type":"string","description":"Stable identifier for the key. A one-way hash, not the secret, so it is safe to store and log. Use it in get, update, and delete calls."},"name":{"type":["string","null"],"description":"User-set name for the key."},"label":{"type":"string","description":"Display label (the key's public prefix, e.g. `mg_8Kx2pQ`). Not the secret."},"disabled":{"type":"boolean","description":"Whether the key is disabled. A disabled key cannot call the gateway but is not deleted."},"limit":{"type":["number","null"],"format":"double","description":"Spend cap in USD over the reset window. Null means no cap."},"limit_reset":{"$ref":"#/components/schemas/KeyLimitReset","description":"Window the spend cap resets on. Resets at midnight UTC."},"usage":{"type":"number","format":"double","description":"Spend in USD in the current reset window."},"limit_remaining":{"type":["number","null"],"format":"double","description":"Remaining spend in USD before the cap. Null when no limit is set."},"created_at":{"type":["string","null"],"format":"date-time","description":"When the key was created."}},"required":["hash","label","disabled","usage"],"description":"An API key with its current usage and spend limit.","title":"Key"},"KeyList":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Key"}},"has_more":{"type":"boolean","description":"True when more keys remain beyond this page. Advance with offset until it is false."}},"title":"KeyList"},"Error":{"type":"object","properties":{"detail":{"type":"string","description":"Human-readable error message."}},"title":"Error"},"CreateKeyRequestLimitReset":{"type":"string","enum":["daily","weekly","monthly"],"description":"Window the spend cap resets on. Required if `limit` is set.","title":"CreateKeyRequestLimitReset"},"CreateKeyRequest":{"type":"object","properties":{"name":{"type":["string","null"],"description":"A name for the key, for example `customer-acme` or `alice@acme.com`. Shown in the dashboard and usage views."},"limit":{"type":["number","null"],"format":"double","description":"Optional spend cap in USD over the reset window."},"limit_reset":{"$ref":"#/components/schemas/CreateKeyRequestLimitReset","description":"Window the spend cap resets on. Required if `limit` is set."}},"title":"CreateKeyRequest"},"KeyCreatedLimitReset":{"type":"string","enum":["daily","weekly","monthly"],"description":"Window the spend cap resets on. Resets at midnight UTC.","title":"KeyCreatedLimitReset"},"KeyCreated":{"type":"object","properties":{"hash":{"type":"string","description":"Stable identifier for the key. A one-way hash, not the secret, so it is safe to store and log. Use it in get, update, and delete calls."},"name":{"type":["string","null"],"description":"User-set name for the key."},"label":{"type":"string","description":"Display label (the key's public prefix, e.g. `mg_8Kx2pQ`). Not the secret."},"disabled":{"type":"boolean","description":"Whether the key is disabled. A disabled key cannot call the gateway but is not deleted."},"limit":{"type":["number","null"],"format":"double","description":"Spend cap in USD over the reset window. Null means no cap."},"limit_reset":{"$ref":"#/components/schemas/KeyCreatedLimitReset","description":"Window the spend cap resets on. Resets at midnight UTC."},"usage":{"type":"number","format":"double","description":"Spend in USD in the current reset window."},"limit_remaining":{"type":["number","null"],"format":"double","description":"Remaining spend in USD before the cap. Null when no limit is set."},"created_at":{"type":["string","null"],"format":"date-time","description":"When the key was created."},"key":{"type":"string","description":"The raw API key (prefixed `mg_`). Shown exactly once, at creation. Store it now; it cannot be retrieved later."}},"required":["hash","label","disabled","usage","key"],"description":"A newly created key. `key` is the raw secret and is returned only here.","title":"KeyCreated"},"UpdateKeyRequestLimitReset":{"type":"string","enum":["daily","weekly","monthly"],"description":"New reset window.","title":"UpdateKeyRequestLimitReset"},"UpdateKeyRequest":{"type":"object","properties":{"name":{"type":["string","null"],"description":"New name for the key."},"disabled":{"type":["boolean","null"],"description":"Set true to disable the key, false to re-enable it."},"limit":{"type":["number","null"],"format":"double","description":"New spend cap in USD."},"limit_reset":{"$ref":"#/components/schemas/UpdateKeyRequestLimitReset","description":"New reset window."}},"description":"Only the fields you send are changed.","title":"UpdateKeyRequest"},"RoutingPolicyStrategy":{"type":"string","enum":["PRIORITY","INTELLIGENT"],"title":"RoutingPolicyStrategy"},"PriorityEntry":{"type":"object","properties":{"model":{"type":"string","description":"Canonical model slug (provider/model)."},"priority":{"type":"integer","description":"Lower tries first."}},"required":["model","priority"],"title":"PriorityEntry"},"RoutingPolicyAxis":{"type":"string","enum":["COST","PERFORMANCE","CAPABILITY"],"description":"Optimization axis the router optimizes for (INTELLIGENT only, else null); one of COST, PERFORMANCE, CAPABILITY.","title":"RoutingPolicyAxis"},"RoutingPolicy":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"slug":{"type":["string","null"],"description":"The policy's model alias (bare name), e.g. \"fast-experiment\". Null only when no alias could be minted, such as an organization at its alias cap."},"model":{"type":["string","null"],"description":"The ready-to-send model string for this policy, e.g. \"@alias/fast-experiment\". Send it as the model in any Gateway request to route with this policy."},"strategy":{"$ref":"#/components/schemas/RoutingPolicyStrategy"},"allowed_providers":{"type":"array","items":{"type":"string"}},"allowed_models":{"type":"array","items":{"type":"string"}},"priority_order":{"type":"array","items":{"$ref":"#/components/schemas/PriorityEntry"}},"axis":{"$ref":"#/components/schemas/RoutingPolicyAxis","description":"Optimization axis the router optimizes for (INTELLIGENT only, else null); one of COST, PERFORMANCE, CAPABILITY."},"created_at":{"type":"string","format":"date-time"},"modified_at":{"type":"string","format":"date-time"}},"description":"The project's scoped routing policy. The id is stable across updates (updates apply in place).","title":"RoutingPolicy"},"BudgetConfigPeriod":{"type":"string","enum":["daily","weekly","monthly","quarterly","yearly"],"title":"BudgetConfigPeriod"},"BudgetConfigEnforcementMode":{"type":"string","enum":["hard_limit","soft_limit"],"title":"BudgetConfigEnforcementMode"},"BudgetConfig":{"type":"object","properties":{"amount":{"type":"number","format":"double","exclusiveMinimum":0,"description":"Budget amount in USD."},"period":{"$ref":"#/components/schemas/BudgetConfigPeriod"},"enforcement_mode":{"$ref":"#/components/schemas/BudgetConfigEnforcementMode"},"alert_thresholds":{"type":"array","items":{"type":"integer","minimum":1,"maximum":100},"description":"Alert percentages, e.g. [80, 90]."},"notification_emails":{"type":"array","items":{"type":"string","format":"email"},"description":"Addresses emailed when a threshold is reached. Recipients do not need a Merge account."},"notify_org_admins":{"type":"boolean","default":true,"description":"Email every organization admin alongside notification_emails. Naming recipients adds to the audience rather than replacing it; set false to email only the named recipients. While notification_emails is empty, one admin is notified."}},"required":["amount","period","enforcement_mode"],"description":"Project spending limit. hard_limit rejects requests with HTTP 402 once reached; soft_limit alerts only.","title":"BudgetConfig"},"Project":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"organization_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string","description":"Derived from name; unique within the organization."},"description":{"type":"string"},"is_active":{"type":"boolean"},"uses_organization_default_routing":{"type":"boolean","description":"True when the project routes via the org default policy (no scoped policy)."},"routing_policy":{"oneOf":[{"$ref":"#/components/schemas/RoutingPolicy"},{"type":"null"}]},"budget_config":{"oneOf":[{"$ref":"#/components/schemas/BudgetConfig"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"title":"Project"},"ProjectList":{"type":"object","properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/Project"}},"next":{"type":"string","description":"Opaque cursor for the next page; null when exhausted."},"previous":{"type":"string"}},"title":"ProjectList"},"RoutingPolicyInputStrategy":{"type":"string","enum":["PRIORITY","INTELLIGENT"],"title":"RoutingPolicyInputStrategy"},"RoutingPolicyInputAxis":{"type":"string","enum":["COST","PERFORMANCE","CAPABILITY"],"description":"INTELLIGENT only. Optimization axis the router optimizes for; defaults to COST.","title":"RoutingPolicyInputAxis"},"RoutingPolicyInput":{"type":"object","properties":{"name":{"type":"string","maxLength":255,"description":"Defaults to \"<project name> routing policy\"."},"description":{"type":"string"},"strategy":{"$ref":"#/components/schemas/RoutingPolicyInputStrategy"},"allowed_providers":{"type":"array","items":{"type":"string"},"description":"INTELLIGENT only; derived from allowed_models when omitted."},"allowed_models":{"type":"array","items":{"type":"string"},"description":"INTELLIGENT only."},"priority_order":{"type":"array","items":{"$ref":"#/components/schemas/PriorityEntry"},"description":"PRIORITY only."},"axis":{"$ref":"#/components/schemas/RoutingPolicyInputAxis","description":"INTELLIGENT only. Optimization axis the router optimizes for; defaults to COST."}},"required":["strategy"],"description":"Project-scoped routing policy. PRIORITY requires priority_order; INTELLIGENT requires allowed_models (allowed_providers is derived). The two field sets are mutually exclusive by strategy.","title":"RoutingPolicyInput"},"CreateProjectRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"description":{"type":"string"},"budget_config":{"$ref":"#/components/schemas/BudgetConfig"},"uses_organization_default_routing":{"type":"boolean","default":true},"routing_policy":{"$ref":"#/components/schemas/RoutingPolicyInput"}},"required":["name"],"description":"uses_organization_default_routing=false requires routing_policy; supplying routing_policy with true is rejected (422). Unknown fields are rejected (422).","title":"CreateProjectRequest"},"UpdateProjectRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"description":{"type":"string"},"is_active":{"type":"boolean"},"budget_config":{"$ref":"#/components/schemas/BudgetConfig"},"uses_organization_default_routing":{"type":"boolean"},"routing_policy":{"$ref":"#/components/schemas/RoutingPolicyInput"}},"description":"Sends-only-what-changes. routing_policy is a FULL replacement applied in place (stable policy id); uses_organization_default_routing=true removes the scoped policy.","title":"UpdateProjectRequest"},"ProjectUsageModelSpendGranularity":{"type":"string","enum":["month"],"title":"ProjectUsageModelSpendGranularity"},"ProjectUsage":{"type":"object","properties":{"project_id":{"type":"string","format":"uuid"},"merge_hosted_spend":{"type":"number","format":"double","description":"Managed-credential spend, USD."},"byok_spend":{"type":"number","format":"double","description":"BYOK usage at list price, USD (raw vendor cost is $0 for unpriced customer vendors)."},"web_search_spend":{"type":"number","format":"double","description":"Server-side web search cost, USD."},"total_spend":{"type":"number","format":"double"},"request_count":{"type":"integer"},"model_spend":{"type":"object","additionalProperties":{"type":"number","format":"double"},"description":"Per-model spend, BYOK-corrected, month-granular. Accrues from when per-project model tracking deployed."},"model_spend_granularity":{"$ref":"#/components/schemas/ProjectUsageModelSpendGranularity"},"start":{"type":"string","format":"date"},"end":{"type":"string","format":"date"}},"title":"ProjectUsage"},"PiProtectionOverridePiMode":{"type":"string","enum":["off","alert","block"],"description":"Direct-injection enforcement mode: off, alert, or block","title":"PiProtectionOverridePiMode"},"PiProtectionOverridePiIndirectMode":{"type":"string","enum":["off","alert","block"],"description":"Indirect-injection enforcement mode, a separate axis from pi_mode","title":"PiProtectionOverridePiIndirectMode"},"PiProtectionOverridePiOutputAction":{"type":"string","enum":["observe","redact","route","block","escalate"],"description":"What to do when the response-side check fires","title":"PiProtectionOverridePiOutputAction"},"PiProtectionOverride":{"type":"object","properties":{"pi_mode":{"oneOf":[{"$ref":"#/components/schemas/PiProtectionOverridePiMode"},{"type":"null"}],"description":"Direct-injection enforcement mode: off, alert, or block"},"pi_block_threshold":{"type":["number","null"],"format":"double","minimum":0,"maximum":1,"description":"Direct-injection block threshold. Must be at least the organization's pi_pass_threshold, which is not overridable per project"},"pi_indirect_mode":{"oneOf":[{"$ref":"#/components/schemas/PiProtectionOverridePiIndirectMode"},{"type":"null"}],"description":"Indirect-injection enforcement mode, a separate axis from pi_mode"},"pi_tier2a_block_threshold":{"type":["number","null"],"format":"double","minimum":0,"maximum":1,"description":"Indirect-injection heuristic-confidence threshold"},"pi_tier2b_block_threshold":{"type":["number","null"],"format":"double","minimum":0,"maximum":1,"description":"Indirect-injection embedding-similarity threshold"},"pi_output_action":{"oneOf":[{"$ref":"#/components/schemas/PiProtectionOverridePiOutputAction"},{"type":"null"}],"description":"What to do when the response-side check fires"},"pi_fail_closed":{"type":["boolean","null"],"description":"Whether to reject requests when the detection service is unavailable. Defaults to failing open"},"pi_allowlist_patterns":{"type":["array","null"],"items":{"type":"string"},"description":"Regexes whose matching segments skip scanning. Unioned with the organization's list, never replacing it. A pattern broad enough to match ordinary prose disables enforcement rather than narrowing it"}},"description":"A project's sparse prompt injection override. Every field is optional: omitted means inherit the organization value, null clears the field back to inheritance. Unknown fields are rejected with a 422.","title":"PiProtectionOverride"},"PiProtectionSettings":{"type":"object","properties":{"pi_mode":{"type":"string"},"pi_block_threshold":{"type":"number","format":"double"},"pi_pass_threshold":{"type":"number","format":"double"},"pi_input_action":{"type":"string"},"pi_output_action":{"type":"string"},"pi_allowlist_patterns":{"type":"array","items":{"type":"string"}},"pi_safer_vendor_route":{"type":["string","null"]},"pi_fail_closed":{"type":"boolean"},"pi_log_full_text_on_block":{"type":"boolean"},"pi_indirect_mode":{"type":"string"},"pi_tier2a_block_threshold":{"type":"number","format":"double"},"pi_tier2b_block_threshold":{"type":"number","format":"double"}},"description":"A fully resolved prompt injection policy, with no field left to inherit.","title":"PiProtectionSettings"},"ProjectPiSettings":{"type":"object","properties":{"override":{"$ref":"#/components/schemas/PiProtectionOverride","description":"What this project sets. Fields it does not set are null here"},"effective":{"$ref":"#/components/schemas/PiProtectionSettings","description":"The policy a request to this project runs under, assuming the project is pinned to an API key"},"inherited_fields":{"type":"array","items":{"type":"string"},"description":"Fields taken from the organization policy because the project does not set them"}},"description":"Both layers, so you never merge them yourself.","title":"ProjectPiSettings"},"DlpEntityOverrideAction":{"type":"string","enum":["log","redact","block"],"description":"What to do on a match","title":"DlpEntityOverrideAction"},"DlpEntityOverride":{"type":"object","properties":{"enabled":{"type":["boolean","null"],"description":"Whether this entity is scanned for this project"},"action":{"oneOf":[{"$ref":"#/components/schemas/DlpEntityOverrideAction"},{"type":"null"}],"description":"What to do on a match"}},"description":"A project's override for one entity type. Both fields are optional; omit one to inherit that half from the organization's rule.","title":"DlpEntityOverride"},"ProjectDlpEntityState":{"type":"object","properties":{"entity_type":{"type":"string"},"display_name":{"type":["string","null"]},"category":{"type":"string"},"is_seeded":{"type":"boolean","description":"Whether this entity comes from the seeded rule set"},"org_action":{"type":["string","null"],"description":"What the organization does with it. Null means not scanned"},"effective_action":{"type":["string","null"],"description":"What this project does with it after its override. Null means not scanned"},"overridden":{"type":"boolean","description":"Whether the project overrides this entity"}},"description":"How one entity type resolves for a project.","title":"ProjectDlpEntityState"},"ProjectDlpSettings":{"type":"object","properties":{"override":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/DlpEntityOverride"},"description":"What this project sets, keyed by entity type. Keys the project does not set are absent, and unset halves come back null"},"entities":{"type":"array","items":{"$ref":"#/components/schemas/ProjectDlpEntityState"},"description":"Every entity in the organization's catalog, with the merge applied"}},"description":"The project's override plus the resolved outcome for every entity, so you never merge them yourself.","title":"ProjectDlpSettings"},"ProjectDlpOverrideRequest":{"type":"object","properties":{"override":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/DlpEntityOverride"},"description":"Keyed by entity type, for example US_SSN. An entity must already exist for the organization, either as a seeded rule or a custom one. Defaults to an empty map, which clears the override"}},"description":"Wholesale replacement of a project's DLP override.","title":"ProjectDlpOverrideRequest"},"OrgRoutingPolicyList":{"type":"object","properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/RoutingPolicy"}},"next":{"type":"string","description":"Always null; the org's policies are returned in one page."},"previous":{"type":"string"}},"title":"OrgRoutingPolicyList"},"OrgRoutingPolicyCreateStrategy":{"type":"string","enum":["PRIORITY","INTELLIGENT"],"title":"OrgRoutingPolicyCreateStrategy"},"OrgRoutingPolicyCreateAxis":{"type":"string","enum":["COST","PERFORMANCE","CAPABILITY"],"description":"INTELLIGENT only. Optimization axis the router optimizes for; defaults to COST.","title":"OrgRoutingPolicyCreateAxis"},"OrgRoutingPolicyCreate":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"description":{"type":"string"},"slug":{"type":"string","description":"Explicit model alias for the new policy (bare name, lowercase slug). Omitted: derived from the name, or \"default\" when the policy becomes the organization default. Collisions are suffixed (\"fast\", \"fast-2\")."},"is_default":{"type":"boolean","description":"Make this the org default (unsets the previous default)."},"strategy":{"$ref":"#/components/schemas/OrgRoutingPolicyCreateStrategy"},"allowed_providers":{"type":"array","items":{"type":"string"},"description":"INTELLIGENT only, optional. If provided, must match the providers of allowed_models (it does not filter independently); returned derived from allowed_models on reads."},"allowed_models":{"type":"array","items":{"type":"string"},"description":"INTELLIGENT only."},"priority_order":{"type":"array","items":{"$ref":"#/components/schemas/PriorityEntry"},"description":"PRIORITY only."},"axis":{"$ref":"#/components/schemas/OrgRoutingPolicyCreateAxis","description":"INTELLIGENT only. Optimization axis the router optimizes for; defaults to COST."}},"required":["name","strategy"],"description":"PRIORITY requires priority_order; INTELLIGENT requires allowed_models. The org's first policy becomes the default automatically.","title":"OrgRoutingPolicyCreate"},"OrgRoutingPolicyUpdateStrategy":{"type":"string","enum":["PRIORITY","INTELLIGENT"],"title":"OrgRoutingPolicyUpdateStrategy"},"OrgRoutingPolicyUpdateAxis":{"type":"string","enum":["COST","PERFORMANCE","CAPABILITY"],"description":"INTELLIGENT only. Optimization axis the router optimizes for; defaults to COST.","title":"OrgRoutingPolicyUpdateAxis"},"OrgRoutingPolicyUpdate":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"description":{"type":"string"},"slug":{"type":"string","description":"Renames the policy's model alias. The alias never changes on a policy rename (it is a contract with your clients), so this field is the only way to change it; a name already in use returns 409. Clients still sending the old alias receive 404s."},"is_default":{"type":"boolean"},"strategy":{"$ref":"#/components/schemas/OrgRoutingPolicyUpdateStrategy"},"allowed_providers":{"type":"array","items":{"type":"string"},"description":"INTELLIGENT only, optional. If provided, must match the providers of allowed_models (it does not filter independently); returned derived from allowed_models on reads."},"allowed_models":{"type":"array","items":{"type":"string"}},"priority_order":{"type":"array","items":{"$ref":"#/components/schemas/PriorityEntry"}},"axis":{"$ref":"#/components/schemas/OrgRoutingPolicyUpdateAxis","description":"INTELLIGENT only. Optimization axis the router optimizes for; defaults to COST."}},"description":"Sends-only-what-changes. Include strategy plus its matching fields to change routing (full replacement, applied in place); omit them for a metadata-only update.","title":"OrgRoutingPolicyUpdate"},"V1OrganizationUsageGetParametersGroupBy":{"type":"string","enum":["project","api_key","vendor"],"title":"V1OrganizationUsageGetParametersGroupBy"},"OrganizationUsageModelSpendGranularity":{"type":"string","enum":["month"],"title":"OrganizationUsageModelSpendGranularity"},"OrganizationUsageProjectsItems":{"type":"object","properties":{},"title":"OrganizationUsageProjectsItems"},"OrganizationUsageApiKeysItems":{"type":"object","properties":{},"title":"OrganizationUsageApiKeysItems"},"OrganizationUsage":{"type":"object","properties":{"merge_hosted_spend":{"type":"number","format":"double","description":"Managed-credential spend, USD."},"byok_spend":{"type":"number","format":"double","description":"BYOK usage at list price, USD (raw vendor cost is $0 for unpriced customer vendors)."},"web_search_spend":{"type":"number","format":"double","description":"Server-side web search cost, USD."},"total_spend":{"type":"number","format":"double"},"request_count":{"type":"integer"},"model_spend":{"type":"object","additionalProperties":{"type":"number","format":"double"},"description":"Per-model spend, BYOK-corrected. Month-granular: covers the months the range overlaps."},"model_spend_granularity":{"$ref":"#/components/schemas/OrganizationUsageModelSpendGranularity"},"projects":{"type":"array","items":{"$ref":"#/components/schemas/OrganizationUsageProjectsItems"},"description":"Present with group_by=project."},"api_keys":{"type":"array","items":{"$ref":"#/components/schemas/OrganizationUsageApiKeysItems"},"description":"Present with group_by=api_key."},"vendors":{"type":"object","additionalProperties":{"type":"number","format":"double"},"description":"Present with group_by=vendor."},"start":{"type":"string","format":"date"},"end":{"type":"string","format":"date"}},"title":"OrganizationUsage"}},"securitySchemes":{"ManagementKey":{"type":"http","scheme":"bearer","description":"A management key (prefixed `mgmt_`), created in the dashboard under Settings, API keys, Management keys. Distinct from a regular gateway API key, and never used to call models."}}}}