---
id: service-specification-package-create
title: "Package an existing service specification"
description: "Create a package from a service specification that doesn't belong to a package yet. The server assembles the bill of materials for you, in a single database transaction:"
sidebar_label: "Package an existing service specification"
hide_title: true
hide_table_of_contents: true
api: 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
sidebar_class_name: "post 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={"Package an existing service specification"}
>
</Heading>

<MethodEndpoint
  method={"post"}
  path={"/service_specification/{id}/package"}
  context={"endpoint"}
>
  
</MethodEndpoint>



Create a package from a service specification that doesn't belong to a package yet. The server assembles the bill of materials for you, in a single database transaction:

1. Pins the specification, each of its action specifications, each of its link specifications and each link's action specifications to a snapshot. An entity whose current content matches its latest snapshot reuses that snapshot; otherwise, including an entity with no snapshot yet, a new snapshot is minted.
2. Resolves `sources`. An inline source (`type` and `meta`) registers the artifact, or a new revision of it, under `nrn`. A referenced source (`artifact_id`) pins an existing artifact at `revision_id`, or at its newest revision when you omit it.
3. Creates the package and its first revision with these components:
   - `spec`: the service specification.
   - One component per source, named after the source (`source` when there's a single unnamed source).
   - One component per action specification, named after its slug.
   - One component per link specification, named after its slug.
   - One component per link action specification, named `<link slug>:<action slug>`.

The package's `name` and `slug` default to the specification's, and `visible_to` defaults to `[nrn]`. The response is the same package `POST /packages` returns.

> ℹ️ **Note:** `nrn` must be concrete (no wildcards). The request fails with `409` when the specification already belongs to a package; to publish a new revision of that package, use `PATCH /packages/{id}`.


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

<ParamsDetails
  parameters={[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"description":"The service specification id.","example":"7b2d1c5e-8f4a-4e3b-9c6d-1a2b3c4d5e6f"}]}
>
  
</ParamsDetails>

<RequestSchema
  title={"Body"}
  body={{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["nrn","sources"],"properties":{"nrn":{"type":"string","description":"The owning NRN of the new package. Must be concrete (no wildcards).","example":"organization=1:account=2"},"name":{"type":"string","minLength":1,"description":"Package name. Defaults to the specification's name.","example":"My scope"},"slug":{"type":"string","minLength":1,"description":"Package slug, unique per NRN. Defaults to the specification's slug.","example":"my-scope"},"visible_to":{"type":"array","items":{"type":"string"},"description":"NRNs allowed to consume the package. Defaults to [nrn].","example":["organization=1:account=2"]},"version":{"type":"string","default":"1.0.0","description":"Semver of the first revision.","example":"1.0.0"},"sources":{"type":"array","minItems":1,"description":"The artifacts to include in the bill of materials. With a single source, name is optional and defaults to \"source\"; with several, every source needs a unique name. \"spec\" is reserved.","items":{"description":"Either an inline source that registers an artifact (type and meta) or a reference to an existing artifact (artifact_id). The two shapes are mutually exclusive.","oneOf":[{"title":"Inline artifact","type":"object","required":["type","meta"],"additionalProperties":false,"properties":{"name":{"type":"string","minLength":1,"description":"Component name in the bill of materials."},"type":{"type":"string","enum":["oci_image","oras_artifact","git_repository","blob"],"description":"The artifact type."},"meta":{"type":"object","additionalProperties":true,"description":"The per-type artifact meta blob, validated like POST /artifacts. The artifact, or a new revision of it, is registered under the package's nrn.","example":{"url":"https://github.com/acme/my-service.git","reference":"v1.2.0"}},"visible_to":{"type":"array","items":{"type":"string"},"description":"Visibility of the registered artifact. A new artifact defaults to [nrn]; on an existing artifact, a non-empty value replaces its visibility."}}},{"title":"Referenced artifact","type":"object","required":["artifact_id"],"additionalProperties":false,"properties":{"name":{"type":"string","minLength":1,"description":"Component name in the bill of materials."},"artifact_id":{"type":"string","format":"uuid","description":"An existing artifact you can read, possibly owned elsewhere or published globally."},"revision_id":{"type":"string","format":"uuid","description":"The artifact revision to pin. Defaults to the artifact's newest revision."},"visible_to":{"type":"array","items":{"type":"string"},"description":"Ignored for referenced artifacts: the referenced artifact isn't modified."}}}],"title":"packageFromSpecSource"}}},"title":"packageFromSpec"}}}}}
>
  
</RequestSchema>

<StatusCodes
  id={undefined}
  label={undefined}
  responses={{"200":{"description":"The created package.","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"}}}},"409":{"description":"The service specification already belongs to a package.","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"}}}},"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>


      