---
title: "Create or publish a package by slug"
method: PUT
path: "/packages"
tags: ["Package"]
---

# Create or publish a package by slug

`PUT /packages`

## Request

- Base URL: `https://api.nullplatform.com`
- URL: `https://api.nullplatform.com/packages`
- Auth: HTTP bearer

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`.

## Request body

- PackageUpsert: 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.
  - `nrn` string, required: The owning NRN.
  - `slug` string, required: The package slug, unique per NRN. Together with nrn, it decides whether the call creates or publishes.
  - `name` string: Required when the call creates the package; ignored otherwise.
  - `visible_to` string[]: Visibility of a new package, or the replacement visibility of an existing one. Defaults to [nrn].
  - `default_revision_id` string, uuid, nullable: On an existing package, pin the default to one of its revisions, or null to follow the latest revision.
  - `version` string: Explicit semver for the new revision. Paired with components.
  - `bump` 'patch' | 'minor' | 'major': Relative semver bump from the latest revision. Paired with components. Can't be used when the call creates the package (send version instead).
  - `components` PackageComponent[]: The components to publish. On an existing package they're merged by name onto the current bill of materials unless merge_components is false.
    - `name` string, required: Name of the component within the revision, for example "spec" or "runtime:main". Unique within the revision; opaque to the package server.
    - `resource_type` string, required: Routing key that identifies which owning service resolves resource_id, for example "service_specification", "action_specification", "link_specification" or "artifact".
    - `resource_id` string, uuid, required: UUID of the underlying resource at its owning service.
    - `resource_revision_id` string, uuid, required: UUID of the revision this component pins: a specification snapshot for service, action and link specifications, or an artifact revision for artifacts.
    - `parent_id` string, uuid, nullable: 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.
  - `merge_components` boolean: Overlay components on the current bill of materials by name (true) or replace it (false).
  - `default` boolean: Promote the revision published in this call to default_revision_id. Mutually exclusive with default_revision_id.

## Response `200`

The existing package after the call.

- Package
  - `id` string, uuid: The package id.
  - `nrn` string: The owning NRN.
  - `slug` string: URL-safe identifier, unique per NRN. Derived from name when omitted on create.
  - `name` string: Human-readable display name.
  - `visible_to` string[]: 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.
  - `default_revision_id` string, uuid, nullable: Pinned revision UUID, or null to follow latest_revision_id.
  - `default_version` string, nullable: Server-derived semver of default_revision_id.
  - `latest_revision_id` string, uuid, nullable: Highest-semver revision UUID. Server-managed.
  - `latest_version` string, nullable: Server-derived semver of latest_revision_id.
  - `components` PackageComponent[]: The bill of materials of the resolved revision (default_revision_id, or latest_revision_id when no default is pinned).
    - `name` string, required: Name of the component within the revision, for example "spec" or "runtime:main". Unique within the revision; opaque to the package server.
    - `resource_type` string, required: Routing key that identifies which owning service resolves resource_id, for example "service_specification", "action_specification", "link_specification" or "artifact".
    - `resource_id` string, uuid, required: UUID of the underlying resource at its owning service.
    - `resource_revision_id` string, uuid, required: UUID of the revision this component pins: a specification snapshot for service, action and link specifications, or an artifact revision for artifacts.
    - `parent_id` string, uuid, nullable: 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.
  - `created_at` string, date-time: When the package was created.
  - `updated_at` string, date-time: When the package envelope last changed.

## Other responses

- `201`: The package was created, with its first revision when the call sent components and version.
- `4XX`: Client error responses due to invalid input, missing parameters or insufficient permissions.
- `5XX`: Server error responses.

## Changes

- **2026-09-17** `43b3c1ecdfd8`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/nullplatform/apis/nullplatform-api/changes/packages/put.md)

---

[API](https://skmtc.dev/nullplatform/apis/nullplatform-api.md) - [All operations](https://skmtc.dev/nullplatform/apis/nullplatform-api/llms.txt) - [OpenAPI document](https://skmtc.dev/nullplatform/apis/nullplatform-api/revisions/d3f66bc633d4?raw)
