generated: '2026-08-17' method: searched source: >- https://www.koyeb.com/docs/reference/api + https://www.koyeb.com/changelog + live probes of https://app.koyeb.com/v1/apps and /v1/catalog/regions on 2026-08-17 + derived from openapi/_original/koyeb-openapi.json provider: Koyeb providerId: koyeb description: >- Cross-cutting request/response semantics for the Koyeb REST API — the rules an agent or client must follow regardless of which resource it is calling. Every value here was either read from Koyeb's own docs/spec or observed on a live unauthenticated response; nothing is assumed. api: base_url: https://app.koyeb.com base_url_evidence: >- The Koyeb API reference page embeds its spec viewer config verbatim as {url: "https://api.prod.koyeb.com/public.swagger.json", servers: [{url: "https://app.koyeb.com", description: "Koyeb API"}]}, and the Swagger document itself declares host: app.koyeb.com. The spec is SERVED from api.prod.koyeb.com but the API is CALLED at app.koyeb.com — these are different hosts and both belong to Koyeb. specification: https://api.prod.koyeb.com/public.swagger.json specification_format: Swagger 2.0, generated by grpc-gateway from protobuf service definitions documentation: https://www.koyeb.com/docs/reference/api authentication: style: bearer-token header: 'Authorization: Bearer ' spec_modelling: >- The spec models it as securityDefinitions.Bearer = {type: apiKey, name: Authorization, in: header}. It is functionally an HTTP bearer scheme; the apiKey modelling is a grpc-gateway artefact. token_creation: https://app.koyeb.com/user/settings/api env_vars: - KOYEB_API_TOKEN # CLI and Agent Skills - KOYEB_TOKEN # MCP server scopes: none scope_note: >- Tokens are organization-wide and carry no scopes or permission subsetting. A token that can read a service can also delete it and reveal its secrets. There is no read-only token and no OAuth flow for third-party apps. detail: authentication/koyeb-authentication.yml versioning: scheme: uri-path current: v1 prefix: /v1 note: >- Every path is under /v1. There is no version header, no date-pinning, and no published policy for how a v2 would be introduced. Version drift is instead expressed as duplicate operations inside v1 — see the breaking_change_style block below. breaking_change_style: >- Koyeb adds a new operation alongside the old one rather than versioning the API. The spec carries UpdateApp/UpdateApp2, UpdateService/UpdateService2, UpdateSecret/UpdateSecret2, UpdateUser/UpdateUser2, UpdateUserV2/UpdateUserV22, UpdateProject/UpdateProject2, UpdateCredential/UpdateCredential2 and UpdateOrganization/UpdateOrganization2 — the PUT (full replace) and the PATCH (partial, update_mask) forms of the same resource. Nothing in the contract tells a consumer which is preferred. partial_updates: supported: true style: protobuf-field-mask methods: [PATCH] parameter: update_mask parameter_in: query operations_declaring_it: 17 shipped: '2026-01-23' shipped_source: >- Changelog 2026-01-23 — "Partial Updates Now Valid Using the PATCH Endpoint of the Koyeb API" note: >- update_mask is a comma-separated list of field paths to modify, in google.protobuf.FieldMask form. Omit it on a PUT and the entire resource is replaced. pagination: style: offset-limit request_params: limit: 'query, integer — the number of items to return (declared on 34 operations)' offset: 'query, integer — the offset in the list of items to return (declared on 32 operations)' order: 'query, string — ascending or descending (declared on 11 operations)' response_fields: - limit # the limit echoed back from the request - offset # the offset echoed back from the request - count # the total number of items - has_next # boolean, declared on 16 list replies cursor_support: false note: >- No cursors, no page tokens, no Link headers. Deep pagination is therefore O(offset) and unstable across concurrent writes. Collections are returned under a resource-named key (apps[], services[], ...), never a generic data[]. field_expansion: supported: false note: >- No expand[] / include / fields parameters. Related objects are fetched by following the *_id fields (see data-model/koyeb-data-model.yml). Some list endpoints have a dedicated *ListItem schema that is a thinner projection than the single-resource schema, so a list response is not a substitute for a Get. filtering: style: query-parameters common_filters: [app_id, service_id, deployment_id, regional_deployment_id, instance_ids, name, types, statuses, ids, starting_time, ending_time] note: >- Filters are per-operation and enumerated in the spec. statuses/types take repeated values from closed enums (e.g. deployment statuses PENDING, PROVISIONING, SCHEDULED, CANCELING, CANCELED, ALLOCATING, STARTING, HEALTHY, DEGRADED, UNHEALTHY, STOPPING, STOPPED, ERRORING, ERROR, STASHED, SLEEPING). idempotency: supported: false header: null evidence: >- Zero occurrences of "idempot" in the entire 600 KB published Swagger document, and no idempotency section anywhere in the Koyeb docs. There is no Idempotency-Key header, no request-fingerprint dedupe, and no documented retry-safety contract for POST. consequence: >- A retried CreateApp or CreateService after a timeout may create a duplicate. The only safe retry pattern is read-then-write: call the matching List operation with a name filter (ListApps?name=, ListServices?name=) and reconcile before retrying — which is exactly what the provider's own MCP "deploy" tool does internally. dry_run_substitute: parameter: dry_run parameter_in: query operations: [CreateService, UpdateService, UpdateService2, Compose] note: >- Not idempotency, but the closest safety valve Koyeb ships: dry_run=true validates the request and confirms the resource exists without creating a deployment. UpdateService additionally accepts save_only (store settings without deploying) and skip_build (reuse the last successful build). request_tracing: request_id_header: null correlation_support: false note: >- No X-Request-Id / X-Correlation-Id is documented or returned. Live responses carry only date, content-type, cache-control, pragma, strict-transport-security and the x-ratelimit-* trio, so there is no server-side handle to quote in a support ticket. error_envelope: content_type: application/json rfc9457: false shape: '{status: int, code: string, message: string}' validation_shape: '{status: int, code: string, message: string, fields: [{field, description}]}' catch_all_shape: 'google.rpc.Status — {code: int (google.rpc.Code, not HTTP), message: string, details: [Any]}' observed: '{"status":401, "code":"authentication_error", "message":"Route needs to be authenticated"}' detail: errors/koyeb-problem-types.yml rate_limit_signaling: headers_returned: - x-ratelimit-limit # e.g. "400, 400;w=60" - x-ratelimit-remaining # e.g. "399" - x-ratelimit-reset # seconds until the window resets, e.g. "58" retry_after: false present_on: every response including 401s and unauthenticated 200s exhaustion_status: 429 (not declared on any operation in the spec) detail: rate-limits/koyeb-rate-limits.yml metadata: user_defined_metadata: false note: >- No metadata{} bag on any resource. Labelling is done with the resource name and, for organizations, the project/sub-organization hierarchy. streaming_and_events: asyncapi_published: false webhooks_published: false event_model: poll-only event_endpoints: - GET /v1/app_events - GET /v1/service_events - GET /v1/deployment_events - GET /v1/regional_deployment_events - GET /v1/instance_events - GET /v1/volume_events - GET /v1/instance_snapshot_events websocket_endpoints: - wss://app.koyeb.com/v1/streams/instances/exec - GET /v1/streams/logs/tail - GET /v1/streams/metrics note: >- Koyeb has a real event surface but it is pull-only: seven *_events collections an agent must poll, plus WebSocket upgrades for exec, log tail and metrics. There are NO outbound webhooks and no published AsyncAPI document, so an integrator cannot be notified that a deployment went HEALTHY — it has to ask. This is why no AsyncAPI or Webhooks pointer is wired into apis.yml. cross_references: authentication: authentication/koyeb-authentication.yml errors: errors/koyeb-problem-types.yml rate_limits: rate-limits/koyeb-rate-limits.yml lifecycle: lifecycle/koyeb-lifecycle.yml data_model: data-model/koyeb-data-model.yml changelog: changelog/koyeb-changelog.yml mcp: mcp/koyeb-mcp.yml maintainers: - FN: Kin Lane email: kin@apievangelist.com