---
id: package-upsert
title: "Create or publish a package by slug"
description: "Create a package, or publish a new revision of an existing one, in a single idempotent call keyed on `nrn` and `slug`."
sidebar_label: "Create or publish a package by slug"
hide_title: true
hide_table_of_contents: true
api: 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
sidebar_class_name: "put api-method"
info_path: docs/api/package
custom_edit_url: null
---

import MethodEndpoint from "@theme/ApiExplorer/MethodEndpoint";
import ParamsDetails from "@theme/ParamsDetails";
import RequestSchema from "@theme/RequestSchema";
import StatusCodes from "@theme/StatusCodes";
import OperationTabs from "@theme/OperationTabs";
import TabItem from "@theme/TabItem";
import Heading from "@theme/Heading";

<Heading
  as={"h1"}
  className={"openapi__heading"}
  children={"Create or publish a package by slug"}
>
</Heading>

<MethodEndpoint
  method={"put"}
  path={"/packages"}
  context={"endpoint"}
>
  
</MethodEndpoint>



Create a package, or publish a new revision of an existing one, in a single idempotent call keyed on `nrn` and `slug`.

- When `nrn` has no package with that slug, creates the package and returns `201`. `name` is required. To publish the first revision in the same call, send `components` with an explicit `version`; `bump` needs a prior revision, so it can't be used here.
- Otherwise, applies the call to the existing package and returns `200`: it publishes a new revision when you send `components`, and updates `visible_to` or `default_revision_id` when you send them. `name` is ignored on this path; rename a package with `PATCH`.

`version` (explicit semver) and `bump` (`patch`, `minor` or `major`, relative to the latest revision) are mutually exclusive, and either one must be paired with `components`. With `merge_components` (default `true`) the components overlay the current bill of materials by name; with `false` the body must list the complete new bill of materials. `default: true` promotes the published revision in the same call.

:::tip PUT or PATCH?
`PUT` is the pipeline-friendly call. It needs no package id, creates the package on the first run, and every later run publishes against the same `nrn` and `slug`, so re-running it is safe. Use `PATCH /packages/{id}` when you already have the id, or to rename the package.
:::

> ℹ️ **Note:** Publishing a bill of materials identical to the latest revision's doesn't create a new revision. Publishing an existing version with a different bill of materials fails with `409`.


<Heading
  id={"request"}
  as={"h2"}
  className={"openapi-tabs__heading"}
  children={"Request"}
>
</Heading>

<ParamsDetails
  parameters={undefined}
>
  
</ParamsDetails>

<RequestSchema
  title={"Body"}
  body={{"content":{"application/json":{"schema":{"type":"object","required":["nrn","slug"],"description":"Idempotent publish keyed on (nrn, slug): creates the package and its first revision when nrn has no package with that slug; publishes a new revision otherwise.","properties":{"nrn":{"type":"string","description":"The owning NRN.","example":"organization=1:account=2"},"slug":{"type":"string","minLength":1,"description":"The package slug, unique per NRN. Together with nrn, it decides whether the call creates or publishes.","example":"my-scope"},"name":{"type":"string","minLength":1,"description":"Required when the call creates the package; ignored otherwise.","example":"My scope"},"visible_to":{"type":"array","items":{"type":"string"},"description":"Visibility of a new package, or the replacement visibility of an existing one. Defaults to [nrn].","example":["organization=1:account=2"]},"default_revision_id":{"type":"string","format":"uuid","nullable":true,"description":"On an existing package, pin the default to one of its revisions, or null to follow the latest revision.","example":"e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b"},"version":{"type":"string","description":"Explicit semver for the new revision. Paired with components.","example":"1.4.0"},"bump":{"type":"string","enum":["patch","minor","major"],"description":"Relative semver bump from the latest revision. Paired with components. Can't be used when the call creates the package (send version instead).","example":"minor"},"components":{"type":"array","items":{"type":"object","required":["name","resource_type","resource_id","resource_revision_id"],"description":"One entry of the bill of materials: a pinned (resource, revision) pair.","properties":{"name":{"type":"string","minLength":1,"description":"Name of the component within the revision, for example \"spec\" or \"runtime:main\". Unique within the revision; opaque to the package server.","example":"spec"},"resource_type":{"type":"string","minLength":1,"description":"Routing key that identifies which owning service resolves resource_id, for example \"service_specification\", \"action_specification\", \"link_specification\" or \"artifact\".","example":"service_specification"},"resource_id":{"type":"string","format":"uuid","description":"UUID of the underlying resource at its owning service.","example":"7b2d1c5e-8f4a-4e3b-9c6d-1a2b3c4d5e6f"},"resource_revision_id":{"type":"string","format":"uuid","description":"UUID of the revision this component pins: a specification snapshot for service, action and link specifications, or an artifact revision for artifacts.","example":"0c9e8d7f-6a5b-4c3d-8e2f-1a0b9c8d7e6f"},"parent_id":{"type":"string","format":"uuid","nullable":true,"description":"The resource_id of the parent component within this revision. Required for action_specification components (the parent is a service or link specification component) and link_specification components (the parent is a service specification component); null for service_specification and artifact components.","example":null}},"title":"packageComponent"},"description":"The components to publish. On an existing package they're merged by name onto the current bill of materials unless merge_components is false."},"merge_components":{"type":"boolean","default":true,"description":"Overlay components on the current bill of materials by name (true) or replace it (false)."},"default":{"type":"boolean","description":"Promote the revision published in this call to default_revision_id. Mutually exclusive with default_revision_id."}},"title":"packageUpsert"}}}}}
>
  
</RequestSchema>

<StatusCodes
  id={undefined}
  label={undefined}
  responses={{"200":{"description":"The existing package after the call.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The package id.","example":"1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"},"nrn":{"type":"string","description":"The owning NRN.","example":"organization=1:account=2"},"slug":{"type":"string","description":"URL-safe identifier, unique per NRN. Derived from name when omitted on create.","example":"my-scope"},"name":{"type":"string","description":"Human-readable display name.","example":"My scope"},"visible_to":{"type":"array","items":{"type":"string"},"description":"NRNs allowed to consume (read and link) this package. Supports trailing-wildcard scopes (for example, \"organization=1:account=*\") and the global wildcard \"organization=*\". Defaults to [nrn]. Modifications stay gated on the owning NRN.","example":["organization=1:account=2"]},"default_revision_id":{"type":"string","format":"uuid","nullable":true,"description":"Pinned revision UUID, or null to follow latest_revision_id.","example":"e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b"},"default_version":{"type":"string","nullable":true,"description":"Server-derived semver of default_revision_id.","example":"1.4.0"},"latest_revision_id":{"type":"string","format":"uuid","nullable":true,"description":"Highest-semver revision UUID. Server-managed.","example":"e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b"},"latest_version":{"type":"string","nullable":true,"description":"Server-derived semver of latest_revision_id.","example":"1.4.0"},"components":{"type":"array","items":{"type":"object","required":["name","resource_type","resource_id","resource_revision_id"],"description":"One entry of the bill of materials: a pinned (resource, revision) pair.","properties":{"name":{"type":"string","minLength":1,"description":"Name of the component within the revision, for example \"spec\" or \"runtime:main\". Unique within the revision; opaque to the package server.","example":"spec"},"resource_type":{"type":"string","minLength":1,"description":"Routing key that identifies which owning service resolves resource_id, for example \"service_specification\", \"action_specification\", \"link_specification\" or \"artifact\".","example":"service_specification"},"resource_id":{"type":"string","format":"uuid","description":"UUID of the underlying resource at its owning service.","example":"7b2d1c5e-8f4a-4e3b-9c6d-1a2b3c4d5e6f"},"resource_revision_id":{"type":"string","format":"uuid","description":"UUID of the revision this component pins: a specification snapshot for service, action and link specifications, or an artifact revision for artifacts.","example":"0c9e8d7f-6a5b-4c3d-8e2f-1a0b9c8d7e6f"},"parent_id":{"type":"string","format":"uuid","nullable":true,"description":"The resource_id of the parent component within this revision. Required for action_specification components (the parent is a service or link specification component) and link_specification components (the parent is a service specification component); null for service_specification and artifact components.","example":null}},"title":"packageComponent"},"description":"The bill of materials of the resolved revision (default_revision_id, or latest_revision_id when no default is pinned)."},"created_at":{"type":"string","format":"date-time","description":"When the package was created.","example":"2026-09-14T12:00:00.000Z"},"updated_at":{"type":"string","format":"date-time","description":"When the package envelope last changed.","example":"2026-09-14T12:00:00.000Z"}},"title":"package"}}}},"201":{"description":"The package was created, with its first revision when the call sent components and version.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The package id.","example":"1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"},"nrn":{"type":"string","description":"The owning NRN.","example":"organization=1:account=2"},"slug":{"type":"string","description":"URL-safe identifier, unique per NRN. Derived from name when omitted on create.","example":"my-scope"},"name":{"type":"string","description":"Human-readable display name.","example":"My scope"},"visible_to":{"type":"array","items":{"type":"string"},"description":"NRNs allowed to consume (read and link) this package. Supports trailing-wildcard scopes (for example, \"organization=1:account=*\") and the global wildcard \"organization=*\". Defaults to [nrn]. Modifications stay gated on the owning NRN.","example":["organization=1:account=2"]},"default_revision_id":{"type":"string","format":"uuid","nullable":true,"description":"Pinned revision UUID, or null to follow latest_revision_id.","example":"e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b"},"default_version":{"type":"string","nullable":true,"description":"Server-derived semver of default_revision_id.","example":"1.4.0"},"latest_revision_id":{"type":"string","format":"uuid","nullable":true,"description":"Highest-semver revision UUID. Server-managed.","example":"e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b"},"latest_version":{"type":"string","nullable":true,"description":"Server-derived semver of latest_revision_id.","example":"1.4.0"},"components":{"type":"array","items":{"type":"object","required":["name","resource_type","resource_id","resource_revision_id"],"description":"One entry of the bill of materials: a pinned (resource, revision) pair.","properties":{"name":{"type":"string","minLength":1,"description":"Name of the component within the revision, for example \"spec\" or \"runtime:main\". Unique within the revision; opaque to the package server.","example":"spec"},"resource_type":{"type":"string","minLength":1,"description":"Routing key that identifies which owning service resolves resource_id, for example \"service_specification\", \"action_specification\", \"link_specification\" or \"artifact\".","example":"service_specification"},"resource_id":{"type":"string","format":"uuid","description":"UUID of the underlying resource at its owning service.","example":"7b2d1c5e-8f4a-4e3b-9c6d-1a2b3c4d5e6f"},"resource_revision_id":{"type":"string","format":"uuid","description":"UUID of the revision this component pins: a specification snapshot for service, action and link specifications, or an artifact revision for artifacts.","example":"0c9e8d7f-6a5b-4c3d-8e2f-1a0b9c8d7e6f"},"parent_id":{"type":"string","format":"uuid","nullable":true,"description":"The resource_id of the parent component within this revision. Required for action_specification components (the parent is a service or link specification component) and link_specification components (the parent is a service specification component); null for service_specification and artifact components.","example":null}},"title":"packageComponent"},"description":"The bill of materials of the resolved revision (default_revision_id, or latest_revision_id when no default is pinned)."},"created_at":{"type":"string","format":"date-time","description":"When the package was created.","example":"2026-09-14T12:00:00.000Z"},"updated_at":{"type":"string","format":"date-time","description":"When the package envelope last changed.","example":"2026-09-14T12:00:00.000Z"}},"title":"package"}}}},"4XX":{"description":"Client error responses due to invalid input, missing parameters or insufficient permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer","example":400},"code":{"type":"string","example":"bad_request"},"error":{"type":"string","example":"Bad Request"},"message":{"type":"string","description":"Human-readable explanation.","example":"Revision '1.4.0' exists with a different bill of materials (revision e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b)"}},"title":"errorResponse"}}}},"5XX":{"description":"Server error responses.","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer","example":400},"code":{"type":"string","example":"bad_request"},"error":{"type":"string","example":"Bad Request"},"message":{"type":"string","description":"Human-readable explanation.","example":"Revision '1.4.0' exists with a different bill of materials (revision e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b)"}},"title":"errorResponse"}}}}}}
>
  
</StatusCodes>


      