Skip to content
GitmoapdocsBeta
Guide· How do I…?

Publishing a provider

Overview

A provider packages pipeline capabilities — a build step, a deploy step, a notifier — as container images plus a manifest saying what each one takes in, what it gives back, and how it is configured. Publishing puts yours in the provider catalog, where other people can install it into their group and wire it into their pipelines. You register once as a publisher, claim a namespace that prefixes everything you ship, and from then on submit one version at a time.

The tier you publish to decides who has to trust what. At the verified tier we review your submission, copy your image into our own registry, sign it and publish it, so consumers trust us rather than you. At the community and private tiers you publish without a review and your registry stays the home of the bytes. A community provider reaches an organisation only once that organisation opts in to the community tier; a private provider belongs to the single organisation you name when you submit, and nobody outside it ever sees that it exists.

Before you start

  • A signed-in account whose email address is confirmed.Registering a publisher with an unconfirmed address is refused with 403. Reading publisher profiles needs nothing more than a signed-in account, but every submit, withdraw and version-lifecycle call is refused with 403 until the calling identity owns a publisher.
  • A namespace you are willing to keep.Three to thirty-two characters, lowercase letters, digits and hyphens, no hyphen at either end. It is claimed first-come, it is unique across the whole platform, it prefixes the id of every provider you ever ship, and it cannot be changed afterwards. The names an organisation cannot take are refused here too: words Gitmoap keeps, well-known organisations' names, and names that look like one — see How organisation names work.
  • Container images already pushed to a registry, with an image reference per capability, each a fully-qualified name that includes the registry host — ghcr.io/acme/deploy-provider:v1.0.0 — together with its sha256: digest. A bare name such as deploy:latest is refused, because a name with no registry host is ambiguous about where the bytes came from. The image has to be pullable without credentials: a submission that carries registry credentials is refused with 400 at every tier.
  • A manifest for the version.It states a contract version of 1, a provider block — the id, a name, a description, and the shape of the credentials a connection to the provider supplies — and between one and thirty-two capabilities. Each capability declares an id prefixed by the provider id (acme.deploy:push), the pipeline stage it belongs to, a name, a description written for whoever will use it, its input and output ports, its configuration schema, and a default timeout, which is 1800 seconds if you leave it out.
  • Token scopes, if you are calling the API or the CLI rather than clicking: publisher:read to read publishers, publisher:manage to register, update and verify your own, provider_publishing:read to follow submissions, provider_publishing:write to submit, withdraw and change a version's lifecycle. Scopes are fixed when a token is minted, so a release pipeline that only submits should carry only provider_publishing:write.
  • A verified namespace, if you want the verified tier.Publishing to community or private needs nothing more than an active publisher; the verified tier requires that your namespace has been proven first. A submission that names no tier asks for verified, so name the tier you want explicitly.
  • Maintainer on a root group, if you want the private tier.A private provider belongs to exactly one organisation, and you name that top-level group when you submit. Naming a subgroup, or naming a group at any other tier, is refused with 400.

How it works

Three tiers, three trust stories

TierWho may publishWhere the image lives at run timeGate before it publishesWho can install it
verifieda publisher whose namespace is verifiedour registry — we copy and sign your imagehuman review, then the copy-and-sign stepevery organisation, by default
communityany active publisheryour registry, unchangedan automated check that the digest you attested really resolvesonly organisations that have opted in to community providers
privateany active publisher who is a Maintainer of the owning top-level groupyour registry, unchangedthe same automated digest checkonly the organisation you named, which accepts its own private providers unless it turns that off
platformnobody outside the platform teamour registry—everyone

Asking for the platform tier in a submission is refused with 403. You cannot assign yourself the verified tier either: you ask for it, and passing review is what confers it. The two self-service tiers you do assign, because their trust signal is the consuming organisation's own opt-in rather than anything we assert.

A submission that leaves the tier out asks for verified. That is the strictest reading of an omission, and it is the usual cause of a first submission being refused with 403 for an unverified namespace — name community explicitly if that is what you meant.

A provider's tier is fixed at its first publication. A later version of the same provider must ask for the tier it already has; moving a community provider to verified means publishing it again under a new id.

Namespaces and provider ids

A provider id is {namespace}.{slug} — acme.deploy, acme.notify. An id with no dot belongs to the platform's own providers (git, docker, aws) and is refused for anyone else. Because your namespace is unique, provider-id uniqueness follows: nobody else can ship acme.anything, and you cannot ship under somebody else's prefix.

Verifying your namespace proves you control the domain or the code-hosting organisation it names. It earns two things: eligibility for the verified tier, and a badge on every provider you publish, which is what an organisation running a verified_only community policy looks at.

What a submission goes through

Nothing about publishing is synchronous. Submitting answers 202 with a submission id and a state of submitted; everything after that happens on its own and you follow it by reading the submission.

verified tier
submitted ──► approved ──► mirroring ──► published
│ │
│ └──► mirror_failed (final)
├──► changes_requested (final; fix it and submit again)
└──► rejected (final)
community and private tiers
submitted ──► verifying ──► published
└──► verification_failed (final; fix the digest, submit again)
any tier, until approval or a final state
submitted / verifying ──► withdrawn (final; you pulled it)

Copying and signing both happen inside mirroring; there is no separate step you can see or influence.

changes_requested and rejected both carry the reviewer's reason, and neither can be edited in place: the fix is a fresh submission. A (provider, version) pair is held while a submission for it is still open, and is free again the moment that submission is rejected, has changes requested, is withdrawn, or fails — so the same version number is available for a corrected manifest.

What the platform sets, and what stays yours

At the verified tier the image reference you send is a source, not a destination. The published capability points at our copy of your image and carries the digest we recorded when we pushed it, and we sign that copy with our own key. At the community and private tiers the published reference is yours, unchanged, pinned to the digest you attested and confirmed once at publish time.

Either way, what runs is pinned to an exact digest. Pushing new bytes behind the same tag changes nothing for anyone already running your provider — and there is no way to change a published version, because a published (provider, version) pair is immutable. A correction is a new version.

The provider itself — its name, its description and the shape of the credentials a connection supplies — is taken from the first version that publishes. Later versions carry the same provider block, and anything you change in it is ignored. Only the capabilities, their images and the release notes move from version to version.

Release notes are the one piece of prose that rides along with a version: up to 64 KB of markdown, fixed once the version publishes. Everything else you write about the provider — the long description people read on its page, the categories and keywords they find it by, the worked examples — lives on the provider's marketplace listing, which you edit at any time without republishing anything. See Using providers.

How to

Register as a publisher

Registration is self-service and binds the publisher to the identity that calls it — your user account, or a service account if a release pipeline is going to do the publishing. One identity owns at most one publisher, so decide which identity should hold it before you call.

Pick the namespace carefully. It is the only field you cannot change later, and it is visible to everyone who ever browses one of your providers.

Open Marketplace, then Become a publisher. Fill in the namespace, a display name and a contact address, and choose Register. Registering is refused until your account's email address is confirmed. On success you land on your Publisher dashboard, showing your namespace, an unverified badge and an empty list of providers.

Terminalbash
gitmoap provider-publishing register-publisher \
--contact-email <contact email> \
--display-name <display name> \
--namespace <namespace>
curlbash
curl -X POST https://api.gitmoap.example/publishers \
-H "Authorization: Bearer $GITMOAP_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "contact_email": "<string>", "display_name": "<string>", "namespace": "<string>" }'

A new publisher starts unverified and active. That is enough to publish to community and private straight away; the verified tier waits until you have proven the namespace. The response carries the publisher id every later call needs, so keep it — you can also find it again from the publisher list.

Prove you own your namespace

Verification is two calls with a manual step in between: ask for a challenge, place the token it gives you, then ask us to look for it. There are two methods, dns and github, and the target you name has to correspond to your namespace — a domain whose first label is your namespace, or a GitHub organisation whose login is your namespace. Anything else is refused with 400, which is what stops namespace acme being verified through notacme.com. A namespace that is a well-known organisation's name is held to more: only dns proves it, and only on a domain that organisation owns, so microsoft is proven at microsoft.com and never at a name somebody created on a shared DNS service, such as microsoft.mooo.com. A namespace Gitmoap keeps for itself is never proven, and the challenge answers 403.

Open your Publisher dashboard and choose Verify namespace. Pick DNS or GitHub, type the domain or organisation login, and choose Get token. The panel then shows the token, exactly where to place it, and when the challenge expires.

Terminalbash
gitmoap provider-publishing request-namespace-challenge \
--publisher-id <id> \
--method manual|dns|github \
--target <target>
curlbash
curl -X POST https://api.gitmoap.example/publishers/{publisher_id}/verification-challenge \
-H "Authorization: Bearer $GITMOAP_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "method": "<one of dns | github | manual>", "target": "<string>" }'

Place the token where the instructions say. For dns, that is a TXT record at _gitmoap-challenge.<your domain> whose value is the token. For github, it is a verification.txt file at the root of a public <your org>/.gitmoap repository, on its main branch, containing the token. Then come back and finish.

Note

A challenge lives for 72 hours and there is only one pending at a time, so requesting a second challenge replaces the first and invalidates the token you were given. DNS records also take time to propagate; if the check misses, wait for your record's TTL and run the check again with the same token rather than requesting a new one.

Back on Verify namespace, choose Check now. On success the dashboard flips to a verified badge and records which method proved it. A miss leaves the challenge in place so you can fix the record and check again.

Terminalbash
gitmoap provider-publishing verify-namespace-challenge --publisher-id <id>
curlbash
curl -X POST https://api.gitmoap.example/publishers/{publisher_id}/verification-challenge/verify \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Verifying is idempotent: checking an already-verified publisher answers 200 with its current state rather than failing, so a script that runs the check twice is safe.

Asking for manual as the method is refused with 400. A manual grant is a decision platform staff make on your behalf, and it is the route when neither the DNS nor the GitHub proof fits your namespace — write to us instead of calling for it.

Look up a publisher

Publisher profiles are public to anyone signed in, which is how a consumer weighing up a provider finds out who is behind it and whether the namespace is proven. The bound identity behind a publisher is not public — you see it on your own publisher, and platform staff see it everywhere.

Open Marketplace, then Publishers. The list pages through every publisher with its namespace, display name and verification badge. Switch the Verified only toggle to hide unverified namespaces.

Terminalbash
gitmoap provider-publishing list-publishers
curlbash
curl -X GET https://api.gitmoap.example/publishers \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Choose any publisher from the list, or follow the publisher link on a provider's page, to open its profile: namespace, display name, contact address, verification badge and the method that earned it.

Terminalbash
gitmoap provider-publishing get-publisher --publisher-id <id>
curlbash
curl -X GET https://api.gitmoap.example/publishers/{publisher_id} \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Update your publisher profile

The display name, the contact address and the public key are yours to change at any time. The namespace, the account status and the verification badge are not: the first is permanent, and the other two are ours to set.

On your Publisher dashboard, choose Edit profile, change the display name, contact address or public key, and Save.

Terminalbash
gitmoap provider-publishing update-publisher --publisher-id <id>
curlbash
curl -X PATCH https://api.gitmoap.example/publishers/{publisher_id} \
-H "Authorization: Bearer $GITMOAP_TOKEN"

The public key is recorded on your profile and shown with it. It is not what signs a Verified image: we sign our copy of your image with our own key.

Keep the contact address current. It is where a reviewer's questions land, and it is what a consumer with a broken pipeline will use.

Submit a new provider

Use this for the very first version of a provider that is not in the catalog yet. It creates a submission, not a catalog entry — nothing about the provider is visible to anyone else until the submission reaches published.

The body carries the whole candidate version: a contract version of 1, the provider block, the version, every capability with its image reference and digest, the tier you are asking for, the owning group if the tier is private, and optional release notes. Between one and thirty-two capabilities, each with an id prefixed by the provider id, each with a digest of the exact form sha256: followed by sixty-four hex characters. The body accepts no fields beyond the ones the card lists — a misspelt field name is a 400, not a silently ignored value.

Open your Publisher dashboard and choose New provider. Paste or upload the manifest, choose the tier, add the image reference and digest for each capability, and choose Submit for publication. The app takes you straight to Submission tracking for the submission it just created.

Terminalbash
gitmoap provider-publishing submit-provider \
--capabilities '<json>' \
--contract-version <n> \
--provider '<json>' \
--version <version>
curlbash
curl -X POST https://api.gitmoap.example/providers \
-H "Authorization: Bearer $GITMOAP_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "capabilities[].capability_id": "<string>", "capabilities[].description": "<string>", "capabilities[].image_digest": "<string>", "capabilities[].image_ref": "<string>", "capabilities[].name": "<string>", "capabilities[].stage_type": "<one of build | custom | deploy | notify | publish | source | test>", "contract_version": "<int32>", "provider.auth_schema": "<object>", "provider.description": "<string>", "provider.id": "<string>", "provider.name": "<string>", "version": "<string>" }'

Write the descriptions for the people who will use the provider, not for yourself. A capability's description is what somebody reads when they are deciding whether to pick it; a port's description is rendered beside that port in the pipeline editor, so it should say what flows through, what to connect it to and what happens if you leave it unwired — never a container path or an internal error code. A port description is optional and capped at 400 characters, but a port that ships without one leaves whoever wires it guessing.

Submit a new version of a provider you own

Once a provider exists, further versions go to its own submission endpoint. Ownership is checked against your publisher, the manifest's provider id has to match the one in the URL, and the tier has to match the tier the provider already has. A provider that has never published answers 404 here — its first version goes through the new-provider call instead.

Version numbers are strict: a leading v and three numeric parts, v1.0.0. No pre-release suffix, no build metadata, no ranges, no latest. A version that has already published is refused with 409, because a published version is immutable.

Open the provider from your Publisher dashboard, choose Versions, then New version. The provider block is fixed and read-only; fill in the new version number, the capabilities with their new image digests and the release notes, then Submit for publication.

Terminalbash
gitmoap provider-publishing submit-provider-version \
--provider-id <id> \
--capabilities '<json>' \
--contract-version <n> \
--provider '<json>' \
--version <version>
curlbash
curl -X POST https://api.gitmoap.example/providers/{provider_id}/versions \
-H "Authorization: Bearer $GITMOAP_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "capabilities[].capability_id": "<string>", "capabilities[].description": "<string>", "capabilities[].image_digest": "<string>", "capabilities[].image_ref": "<string>", "capabilities[].name": "<string>", "capabilities[].stage_type": "<one of build | custom | deploy | notify | publish | source | test>", "contract_version": "<int32>", "provider.auth_schema": "<object>", "provider.description": "<string>", "provider.id": "<string>", "provider.name": "<string>", "version": "<string>" }'

Follow a submission to the end

A submission is the only place the outcome lives. Read it to see the current state, the reviewer's notes if a decision has been made, and — once it has published — the digests that were recorded.

Open Submission tracking from your Publisher dashboard, or follow the link the submit action gave you. The page shows a progress stepper for the state machine above, the reviewer's notes where there are any, and the resolved image digests once publication finishes.

Terminalbash
gitmoap provider-publishing get --submission-id <id>
curlbash
curl -X GET https://api.gitmoap.example/provider-submissions/{submission_id} \
-H "Authorization: Bearer $GITMOAP_TOKEN"

A failed self-service check writes its reason into the same notes field a reviewer would use, so verification_failed tells you what did not resolve without your having to guess.

Open a provider from your Publisher dashboard and choose Submissions to see every attempt at every version, newest first, each with its state and its version.

Terminalbash
gitmoap provider-publishing list --provider-id <id>
curlbash
curl -X GET https://api.gitmoap.example/providers/{provider_id}/submissions \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Both reads are restricted to the owning publisher and platform staff, because a submission carries review notes that are nobody else's business. Once a submission reads published, the version is in the catalog and an organisation that accepts your tier can install it — see Using providers for what a consumer does next.

Withdraw a submission

Warning

Withdrawing is final. The submission stops where it is and can never be reopened, its review notes stay with it, and the only route forward is a brand-new submission of the same version. Nothing already published is affected — a withdrawal touches the submission, never the catalog.

Withdraw when you spot a mistake before a decision has been taken, or when you want to free a version slot so you can submit a corrected manifest under the same version number.

Open the submission in Submission tracking and choose Withdraw. The confirmation names the provider and version; withdrawal is immediate.

Terminalbash
gitmoap provider-publishing withdraw --submission-id <id>
curlbash
curl -X DELETE https://api.gitmoap.example/provider-submissions/{submission_id} \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Withdrawal is only possible while the submission is still waiting on a decision or still being checked. Once it has been approved — which is when the copy-and-sign work starts — or once it has reached any final state, the call is refused with 409, because approved work holds platform resources a withdrawal cannot cleanly interrupt. A submission that already ended in changes_requested or rejected is final too: there is nothing left to withdraw, and its version slot is free already.

Deprecate a version

Deprecating is how you steer consumers off an old version without breaking them. A deprecated version still runs, and pipelines pinned to it keep working; what changes is that a pipeline referencing it gets a non-blocking warning when it is validated, and the version shows as deprecated wherever it is listed.

Open the provider from your Publisher dashboard, choose Versions, and use Deprecate on the version's row. The version list marks it deprecated straight away.

Terminalbash
gitmoap provider-publishing deprecate-provider-version \
--provider-id <id> \
--version <id>
curlbash
curl -X POST https://api.gitmoap.example/providers/{provider_id}/versions/{version}/deprecate \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Deprecating does not remove the version from the list of versions a pipeline may pin, and it does not change which version is newest — a deprecated version can still be the latest one. Deprecating an already-deprecated version is a no-op. A version that has been sunset cannot be deprecated, and the request answers 409: sunset is permanent. If a version has to stop working altogether, that is a platform decision with a grace window attached, not a publisher one — ask us.

Bring a deprecated version back

Deprecation is reversible. Restoring returns the version to active, and the warning consumers were seeing stops.

On the same Versions list, use Restore on a deprecated version's row.

Terminalbash
gitmoap provider-publishing undeprecate-provider-version \
--provider-id <id> \
--version <id>
curlbash
curl -X POST https://api.gitmoap.example/providers/{provider_id}/versions/{version}/undeprecate \
-H "Authorization: Bearer $GITMOAP_TOKEN"

A version that has been sunset by the platform is a different matter and cannot be restored this way; the call answers 409. Deprecate and restore are the only two lifecycle moves a publisher has. Sunsetting is a platform action, taken with a grace window attached, and no call reverses it — the way past a sunset version is a replacement version.

Reference

13 endpoints

POST/publisherspublisher:manage

Register a publisher bound to the calling identity, claiming a namespace.

register_publisherPOST /publishersOpen in the API reference

Token scope

publisher:manage

Counts against

publishers_per_owner

Send

Body
  • contact_emailstring
  • display_namestring
  • namespacestring
  • public_keyobjectoptional

Refuses

  • 400
  • 401
  • 403
  • 409
  • 429Publisher limit reached for this owner

Receive

  • contact_emailstring
  • created_atstring
  • display_namestring
  • namespacestring
  • ownerobjectoptional
  • public_keyobjectoptional
  • publisher_iduuid
  • statusactivesuspendedAccount status of a Publisher. Active publishers may submit; Suspended is a platform-admin hold.
  • updated_atstring
  • verification_methodobjectoptional
  • verification_targetobjectoptional
  • verifiedboolean
  • verified_atobjectoptional
GET/publishers/{publisher_id}publisher:read

Get a publisher's public profile.

get_publisherGET /publishers/{publisher_id}Open in the API reference

Token scope

publisher:read

Send

Path
  • publisher_iduuidPublisher id

Refuses

  • 400Bad request — a path parameter is not a well-formed value of its type
  • 401
  • 403Forbidden — the caller's access level or token scope is insufficient
  • 404

Receive

The same shape register_publisher returns — 13 fields. Go to it

Show it here
  • contact_emailstring
  • created_atstring
  • display_namestring
  • namespacestring
  • ownerobjectoptional
  • public_keyobjectoptional
  • publisher_iduuid
  • statusactivesuspendedAccount status of a Publisher. Active publishers may submit; Suspended is a platform-admin hold.
  • updated_atstring
  • verification_methodobjectoptional
  • verification_targetobjectoptional
  • verifiedboolean
  • verified_atobjectoptional
GET/publisherspublisher:read

List publishers, paginated.

list_publishersGET /publishersOpen in the API reference

Token scope

publisher:read

Send

Query
  • verifiedbooleanoptionalFilter by verified flag
  • limitint32optionalPage size (1-100, default 20)
  • next_tokenstringoptionalOpaque pagination cursor

Refuses

  • 401
  • 403Forbidden — the caller's access level or token scope is insufficient

Receive

  • items[]object13 fields
    • contact_emailstring
    • created_atstring
    • display_namestring
    • namespacestring
    • ownerobjectoptional
    • public_keyobjectoptional
    • publisher_iduuid
    • statusactivesuspendedAccount status of a Publisher. Active publishers may submit; Suspended is a platform-admin hold.
    • updated_atstring
    • verification_methodobjectoptional
    • verification_targetobjectoptional
    • verifiedboolean
    • verified_atobjectoptional
  • next_tokenobjectoptional
PATCH/publishers/{publisher_id}publisher:manage

Update a publisher's display name, contact email, or public key

update_publisherPATCH /publishers/{publisher_id}Open in the API reference

Token scope

publisher:manage

Send

Path
  • publisher_iduuidPublisher id
Body
  • contact_emailobjectoptional
  • display_nameobjectoptional
  • public_keyobjectoptional

Refuses

  • 400
  • 401
  • 403
  • 404
  • 409The request conflicts with the resource's current state; `reason` says how

Receive

The same shape register_publisher returns — 13 fields. Go to it

Show it here
  • contact_emailstring
  • created_atstring
  • display_namestring
  • namespacestring
  • ownerobjectoptional
  • public_keyobjectoptional
  • publisher_iduuid
  • statusactivesuspendedAccount status of a Publisher. Active publishers may submit; Suspended is a platform-admin hold.
  • updated_atstring
  • verification_methodobjectoptional
  • verification_targetobjectoptional
  • verifiedboolean
  • verified_atobjectoptional
POST/publishers/{publisher_id}/verification-challengepublisher:manage

Start a namespace ownership challenge

request_namespace_challengePOST /publishers/{publisher_id}/verification-challengeOpen in the API reference

Token scope

publisher:manage

Send

Path
  • publisher_iduuidPublisher id
Body
  • methoddnsgithubmanualHow a publisher's verified flag was earned. Manual is the platform-admin grant (D3); Dns / Github are the self-service namespace-ownership proofs.
  • targetstringThe domain or GitHub organisation being verified. It must match the publisher's namespace.

Refuses

  • 400
  • 401
  • 403
  • 404
  • 409The request conflicts with the resource's current state; `reason` says how

Receive

  • expires_atstring
  • instructionsstring
  • methoddnsgithubmanualHow a publisher's verified flag was earned. Manual is the platform-admin grant (D3); Dns / Github are the self-service namespace-ownership proofs.
  • publisher_iduuid
  • targetstring
  • tokenstring
POST/publishers/{publisher_id}/verification-challenge/verifypublisher:manage

Complete a namespace ownership challenge

verify_namespace_challengePOST /publishers/{publisher_id}/verification-challenge/verifyOpen in the API reference

Token scope

publisher:manage

Send

Path
  • publisher_iduuidPublisher id

Refuses

  • 400Bad request — a path parameter is not a well-formed value of its type
  • 401
  • 403
  • 404
  • 409The request conflicts with the resource's current state; `reason` says how
  • 422
  • 502

Receive

The same shape register_publisher returns — 13 fields. Go to it

Show it here
  • contact_emailstring
  • created_atstring
  • display_namestring
  • namespacestring
  • ownerobjectoptional
  • public_keyobjectoptional
  • publisher_iduuid
  • statusactivesuspendedAccount status of a Publisher. Active publishers may submit; Suspended is a platform-admin hold.
  • updated_atstring
  • verification_methodobjectoptional
  • verification_targetobjectoptional
  • verifiedboolean
  • verified_atobjectoptional
POST/providersprovider_publishing:write

Submit the first version of a new provider for review.

submit_providerPOST /providersOpen in the API reference

Token scope

provider_publishing:write

Counts against

provider_submissions_per_publisher

Send

Body
  • capabilities[]object10 fields
    • cache_enabledbooleanoptional
    • capability_idstring
    • config_schemaobjectoptional
    • default_timeout_secondsint32optional
    • descriptionstring
    • image_digeststring
    • image_refstring
    • namestring
    • requires_dockerbooleanoptional
    • stage_typebuildcustomdeploynotifypublishsourcetestThe pipeline stage a capability belongs to. Maps verbatim to the stage_type field of a capability in gitmoap-provider.yaml.
  • changelogobjectoptional
  • contract_versionint32
  • owning_group_idobjectoptional
  • providerobject4 fields
    • auth_schemaobject
    • descriptionstring
    • idstring
    • namestring
  • registry_pull_secretobjectoptional
  • target_tiercommunityplatformprivateverifiedoptionalHow a pipeline provider is distributed and how much it is vouched for.
  • versionstring

Refuses

  • 400
  • 401Unauthenticated — no credential, or an invalid one
  • 403
  • 409
  • 429Open-submission limit reached for this publisher

Receive

  • provider_idstring
  • stateapprovedchanges_requestedin_reviewmirror_failedmirroringpublishedrejectedsigningsubmittedverification_failedverifyingwithdrawnWhere a provider submission stands, from review through to publication or refusal.
  • submission_iduuid
  • submitted_atstring
  • versionstring
POST/providers/{provider_id}/versionsprovider_publishing:write

Submit a new version of an existing provider you own, for review.

submit_provider_versionPOST /providers/{provider_id}/versionsOpen in the API reference

Token scope

provider_publishing:write

Counts against

provider_submissions_per_publisher

Send

Path
  • provider_idstringProvider id
Body
  • capabilities[]object10 fields
    • cache_enabledbooleanoptional
    • capability_idstring
    • config_schemaobjectoptional
    • default_timeout_secondsint32optional
    • descriptionstring
    • image_digeststring
    • image_refstring
    • namestring
    • requires_dockerbooleanoptional
    • stage_typebuildcustomdeploynotifypublishsourcetestThe pipeline stage a capability belongs to. Maps verbatim to the stage_type field of a capability in gitmoap-provider.yaml.
  • changelogobjectoptional
  • contract_versionint32
  • owning_group_idobjectoptional
  • providerobject4 fields
    • auth_schemaobject
    • descriptionstring
    • idstring
    • namestring
  • registry_pull_secretobjectoptional
  • target_tiercommunityplatformprivateverifiedoptionalHow a pipeline provider is distributed and how much it is vouched for.
  • versionstring

Refuses

  • 400
  • 401Unauthenticated — no credential, or an invalid one
  • 403
  • 404
  • 409
  • 429Open-submission limit reached for this publisher

Receive

The same shape submit_provider returns — 5 fields. Go to it

Show it here
  • provider_idstring
  • stateapprovedchanges_requestedin_reviewmirror_failedmirroringpublishedrejectedsigningsubmittedverification_failedverifyingwithdrawnWhere a provider submission stands, from review through to publication or refusal.
  • submission_iduuid
  • submitted_atstring
  • versionstring
GET/providers/{provider_id}/submissionsprovider_publishing:read

List a provider's submissions

list_provider_submissionsGET /providers/{provider_id}/submissionsOpen in the API reference

Token scope

provider_publishing:read

Send

Path
  • provider_idstringProvider id

Refuses

  • 400Bad request — a path parameter is not a well-formed value of its type
  • 401
  • 403
  • 404Not found — or found and private, which is masked as absent

Receive

  • items[]object6 fields
    • provider_idstring
    • publisher_iduuid
    • stateapprovedchanges_requestedin_reviewmirror_failedmirroringpublishedrejectedsigningsubmittedverification_failedverifyingwithdrawnWhere a provider submission stands, from review through to publication or refusal.
    • submission_iduuid
    • submitted_atstring
    • versionstring
GET/provider-submissions/{submission_id}provider_publishing:read

Get a provider submission

get_provider_submissionGET /provider-submissions/{submission_id}Open in the API reference

Token scope

provider_publishing:read

Send

Path
  • submission_iduuidSubmission id

Refuses

  • 400Bad request — a path parameter is not a well-formed value of its type
  • 401
  • 403
  • 404

Receive

  • attest_resultobjectoptional
  • auth_schemaobject
  • manifestobject22 fields
    • capabilities[]object11 fields
      • cache_enabledboolean
      • capability_idstring
      • config_schemaobjectThe JSON Schema a step's config must satisfy to use this capability.
      • default_timeout_secondsint32
      • descriptionstring
      • image_digestobjectoptionalThe exact build of the capability's container image, when the catalog records one. Pinned so a run cannot pick up a different build behind the same tag.
      • image_uristringThe container image that runs the capability, with an immutable version tag.
      • namestring
      • requires_dockerboolean
      • source_image_refobjectoptionalFor a verified provider, the image's location in its publisher's registry before gitmoap copied it. Absent for providers gitmoap builds itself.
      • stage_typebuildcustomdeploynotifypublishsourcetestThe pipeline stage a capability belongs to. Maps verbatim to the stage_type field of a capability in gitmoap-provider.yaml.
    • changelogobjectoptional
    • contract_versionint32
    • cosign_signature_refobjectoptionalWhere the cosign signature is stored in the registry, when the images are signed.
    • lifecycle_stateactivedeprecatedsunsetoptionalLifecycle state of a published ProviderVersionManifest. Active is the default; Deprecated still runs but the trigger-time validator surfaces a warning; Sunset runs only inside its grace window, after which a trigger referencing it fails validation.
    • manifest_digeststringThe SHA-256 digest of the version's gitmoap-provider.yaml. May be empty.
    • provider_idstring
    • published_atstring
    • published_bystring"platform" for platform-authored providers; a publisher id otherwise.
    • signedbooleanoptionalWhether the version's images are signed with gitmoap's cosign key, as verified and platform providers' are.
    • sunset_atobjectoptionalWhen the version was sunset. Set only for a sunset version.
    • sunset_enforced_atobjectoptionalWhen the sunset's grace period ends. After it, a run that uses the version fails to start.
DELETE/provider-submissions/{submission_id}provider_publishing:write

Withdraw a provider submission

withdraw_provider_submissionDELETE /provider-submissions/{submission_id}Open in the API reference

Token scope

provider_publishing:write

Send

Path
  • submission_iduuidSubmission id

Refuses

  • 400Bad request — a path parameter is not a well-formed value of its type
  • 401
  • 403
  • 404
  • 409

Receive

No body.

POST/providers/{provider_id}/versions/{version}/deprecateprovider_publishing:write

Deprecate a published version

deprecate_provider_versionPOST /providers/{provider_id}/versions/{version}/deprecateOpen in the API reference

Token scope

provider_publishing:write

Send

Path
  • provider_idstringProvider id
  • versionstringVersion

Refuses

  • 400Bad request — a path parameter is not a well-formed value of its type
  • 401Unauthenticated — no credential, or an invalid one
  • 403
  • 404
  • 409

Receive

  • capabilities[]object11 fields
    • cache_enabledboolean
    • capability_idstring
    • config_schemaobjectThe JSON Schema a step's config must satisfy to use this capability.
    • default_timeout_secondsint32
    • descriptionstring
    • image_digestobjectoptionalThe exact build of the capability's container image, when the catalog records one. Pinned so a run cannot pick up a different build behind the same tag.
    • image_uristringThe container image that runs the capability, with an immutable version tag.
    • namestring
    • requires_dockerboolean
    • source_image_refobjectoptionalFor a verified provider, the image's location in its publisher's registry before gitmoap copied it. Absent for providers gitmoap builds itself.
    • stage_typebuildcustomdeploynotifypublishsourcetestThe pipeline stage a capability belongs to. Maps verbatim to the stage_type field of a capability in gitmoap-provider.yaml.
  • changelogobjectoptional
  • contract_versionint32
  • cosign_signature_refobjectoptionalWhere the cosign signature is stored in the registry, when the images are signed.
  • lifecycle_stateactivedeprecatedsunsetoptionalLifecycle state of a published ProviderVersionManifest. Active is the default; Deprecated still runs but the trigger-time validator surfaces a warning; Sunset runs only inside its grace window, after which a trigger referencing it fails validation.
  • manifest_digeststringThe SHA-256 digest of the version's gitmoap-provider.yaml. May be empty.
  • provider_idstring
  • published_atstring
  • published_bystring"platform" for platform-authored providers; a publisher id otherwise.
  • signedbooleanoptionalWhether the version's images are signed with gitmoap's cosign key, as verified and platform providers' are.
  • sunset_atobjectoptionalWhen the version was sunset. Set only for a sunset version.
  • sunset_enforced_atobjectoptionalWhen the sunset's grace period ends. After it, a run that uses the version fails to start.
  • versionstring
POST/providers/{provider_id}/versions/{version}/undeprecateprovider_publishing:write

Restore a deprecated version to active

undeprecate_provider_versionPOST /providers/{provider_id}/versions/{version}/undeprecateOpen in the API reference

Token scope

provider_publishing:write

Send

Path
  • provider_idstringProvider id
  • versionstringVersion

Refuses

  • 400Bad request — a path parameter is not a well-formed value of its type
  • 401Unauthenticated — no credential, or an invalid one
  • 403
  • 404
  • 409

Receive

The same shape deprecate_provider_version returns — 13 fields. Go to it

Show it here
  • capabilities[]object11 fields
    • cache_enabledboolean
    • capability_idstring
    • config_schemaobjectThe JSON Schema a step's config must satisfy to use this capability.
    • default_timeout_secondsint32
    • descriptionstring
    • image_digestobjectoptionalThe exact build of the capability's container image, when the catalog records one. Pinned so a run cannot pick up a different build behind the same tag.
    • image_uristringThe container image that runs the capability, with an immutable version tag.
    • namestring
    • requires_dockerboolean
    • source_image_refobjectoptionalFor a verified provider, the image's location in its publisher's registry before gitmoap copied it. Absent for providers gitmoap builds itself.
    • stage_typebuildcustomdeploynotifypublishsourcetestThe pipeline stage a capability belongs to. Maps verbatim to the stage_type field of a capability in gitmoap-provider.yaml.
  • changelogobjectoptional
  • contract_versionint32
  • cosign_signature_refobjectoptionalWhere the cosign signature is stored in the registry, when the images are signed.
  • lifecycle_stateactivedeprecatedsunsetoptionalLifecycle state of a published ProviderVersionManifest. Active is the default; Deprecated still runs but the trigger-time validator surfaces a warning; Sunset runs only inside its grace window, after which a trigger referencing it fails validation.
  • manifest_digeststringThe SHA-256 digest of the version's gitmoap-provider.yaml. May be empty.
  • provider_idstring
  • published_atstring
  • published_bystring"platform" for platform-authored providers; a publisher id otherwise.
  • signedbooleanoptionalWhether the version's images are signed with gitmoap's cosign key, as verified and platform providers' are.
  • sunset_atobjectoptionalWhen the version was sunset. Set only for a sunset version.
  • sunset_enforced_atobjectoptionalWhen the sunset's grace period ends. After it, a run that uses the version fails to start.
  • versionstring

Limits

One publisher per identity. A second registration from the same account or service account is refused with 409 and nothing is created. If you need a separate namespace, register it from a separate identity — a service account is the usual answer for a namespace that a team, rather than a person, should own.

Twenty open submissions per publisher. A submission occupies a slot from the moment you submit until it settles — published, rejected, changes requested, withdrawn, or failed. An approved one still occupies its slot right through the copy-and-sign step, and so does one the automated digest check is still running against. At twenty, a further submit is refused with 429 TOO_MANY_REQUESTS and no submission is created. Free a slot by withdrawing something you no longer want, or wait for a pending decision.

Thirty-two capabilities per submission, and at least one. A provider bigger than that has to split into two providers under the same namespace.

Field sizes the API checks. When you register or update a publisher: a namespace of 3 to 32 characters and a display name of 1 to 80. When you submit: an image reference of at most 512 characters, a port description of at most 400, and release notes of at most 64 KB. Each of these is refused with 400 and the message names the field.

None of these ceilings move with a plan. They are platform limits on the publishing surface rather than namespace quotas, so they are not on your group's usage page and a plan upgrade does not raise them. If one of them is genuinely in your way, get in touch through the contact address on your publisher profile.

Troubleshooting

403 FORBIDDENon register, mentioning a verified email
Cause
The address on your account has not been confirmed
What to do
Confirm the address from your account settings, then register again. Nothing was created by the failed attempt
403 RESERVED_NAMESPACEon register
Cause
The namespace is a word Gitmoap keeps, a platform provider id, or a well-known organisation's name
What to do
Choose a different namespace. Registering proves no domain, so there is no way to register a reserved name
403 NAME_RESEMBLES_RESERVEDon register
Cause
The namespace looks like a well-known organisation's name — a digit for a letter, a hyphen inside it, or a word such as official or support added
What to do
Choose a different namespace
409 CONFLICTon register, on the namespace
Cause
Somebody else claimed it first
What to do
Pick another namespace. Claims are first-come and are not transferred
409 CONFLICTon register, on the identity
Cause
This account or service account already owns a publisher
What to do
Use the publisher you have, or register from a different identity
400 BAD_REQUESTon register or update, naming a field
Cause
The namespace, the contact address or the display name fails its format rule
What to do
Fix the field named in the message. A namespace is 3 to 32 lowercase letters, digits and hyphens with no hyphen at either end; a display name is 1 to 80 characters
400 BAD_REQUESTon the challenge, about the target
Cause
The domain or organisation you named does not correspond to your namespace — or your namespace is a well-known organisation's name and the target is not a domain that organisation owns
What to do
Use a domain whose first label equals your namespace, or an organisation whose login equals it. For a well-known organisation's name, use dns and the domain the message names. Verifying a namespace through an unrelated target is exactly what this refusal prevents
403 RESERVED_NAMESPACEon the challenge
Cause
The namespace is a word Gitmoap keeps, which no proof releases
What to do
It cannot be verified. Publish to community or private under it, or contact support@gitmoap.com
400 BAD_REQUESTon the challenge, about the method
Cause
The request asked for manual
What to do
Ask for dns or github. A manual grant is not something you can request through the API — write to us from the contact address on your publisher profile
404 NOT_FOUNDon the verify step
Cause
No challenge was ever requested, or the one you had expired after 72 hours
What to do
Request a fresh challenge and place the new token — an expired token is never accepted, even if it is still where you put it
422 UNPROCESSABLE_ENTITYon the verify step
Cause
We reached the target and the token was not there, or did not match
What to do
Check the record or file, wait out your DNS TTL if you only just published it, then run the check again with the same token
502 BAD_GATEWAYon the verify step
Cause
The lookup itself failed — the resolver or the code host did not answer
What to do
Retry. This is a transient failure of the lookup, not a verdict on your token, so nothing needs re-placing
403 FORBIDDENon submit, saying you are not a publisher
Cause
The calling identity owns no publisher, or its publisher is suspended
What to do
Register a publisher from this identity. If a release pipeline is publishing, the service account it runs as needs its own publisher, not yours
403 FORBIDDENon submit, about the namespace
Cause
The provider id is outside your namespace, or has no dot at all
What to do
Prefix the id with your namespace. A dotless id belongs to the platform
403 FORBIDDENon submit, about verification
Cause
You asked for the verified tier with an unverified namespace — including by leaving the tier out, which asks for verified
What to do
Name community explicitly if that is the tier you wanted, or verify the namespace first and resubmit
403 FORBIDDENon submit, about the platform tier
Cause
The request asked for platform
What to do
Choose verified, community or private
400 BAD_REQUESTon submit, about a capability
Cause
A capability id is not prefixed by the provider id, a digest is not sha256: plus 64 hex characters, or an image reference has no registry host
What to do
Fix the capability the message names. Push the image and read its digest from the registry rather than typing one
400 BAD_REQUESTon submit, about registry credentials
Cause
The submission carried registry pull credentials, which are refused at every tier
What to do
Remove them and make the image pullable without authentication. An image the platform cannot fetch anonymously cannot be published
400 BAD_REQUESTon a new provider submit, about the owning group
Cause
The private tier was asked for with no group, with a group that is not a top-level one, or a group was named at a tier other than private
What to do
Name a top-level group when the tier is private, and leave the field out otherwise. On a later version the field is ignored — the owning group is whatever the provider was published to
403 FORBIDDENor 404 NOT_FOUND on a private submit, naming the group
Cause
You are below Maintainer in the group you named, or the group id does not resolve for you
What to do
Ask an Owner there to make you a Maintainer, or take the id from the group's own page. A group you cannot see is reported as absent, not as forbidden
400 BAD_REQUESTon submit, about the contract version
Cause
The manifest declared a contract version other than 1
What to do
Set it to 1. That is the only manifest contract the platform accepts
400 BAD_REQUESTon submit, about the version
Cause
The version is not a leading v plus three numbers
What to do
Write it as v1.4.0. A pre-release suffix, build metadata, a range or latest are all refused
400 BAD_REQUESTon any call, naming a field nobody recognises
Cause
A field name is misspelt, or belongs to a body you were not sending
What to do
Every request body refuses fields it does not know rather than ignoring them, so the name in the message is the typo. Delete it or correct the spelling
400 BAD_REQUESTon a version submit, about the provider id
Cause
The manifest's provider id does not match the one in the URL
What to do
Make them the same. A version submit cannot rename or retarget the provider
409 CONFLICTon submit, saying the provider exists
Cause
You used the new-provider call for a provider that is already in the catalog
What to do
Use the new-version call on that provider instead
409 CONFLICTon submit, saying a submission is open
Cause
Another submission for the same provider and version is still awaiting a decision
What to do
Withdraw it, or wait for it to finish, then submit again. The version slot frees when that submission reaches a final state, not when it is approved
409 CONFLICTon submit, saying the version is published
Cause
That version number has already published, and published versions are immutable
What to do
Bump the version and submit again
409 CONFLICTon submit, about the tier
Cause
The tier you asked for is not the tier the provider already has
What to do
Submit at the provider's existing tier. Tier is fixed at first publication
429 TOO_MANY_REQUESTSon submit
Cause
Twenty of your submissions are open — awaiting review, being checked, or being mirrored
What to do
List your provider's submissions, withdraw the ones you no longer want, and submit again. Nothing was created by the refused call
409 CONFLICTon withdraw
Cause
The submission has been approved, is being mirrored or signed, or has already reached a final state
What to do
There is nothing to withdraw. Let it finish and submit a corrected version, or read the submission to see which final state it landed in
409 CONFLICTon restoring a version
Cause
The version was sunset by the platform, not deprecated by you
What to do
A sunset is not reversible by anyone. Publish a replacement version and move consumers onto it; the version carries the date its grace window ends, and that is your deadline
403 FORBIDDENon a submission read, a lifecycle change, or a publisher edit
Cause
Your publisher does not own that provider or that submission, or the publisher id in the path is somebody else's
What to do
Only the owning publisher and platform staff read review notes, change a version's lifecycle, or edit and verify a publisher. Check you are calling as the identity that registered the publisher
403 INSUFFICIENT_SCOPEon any call
Cause
The token is valid but was minted without the scope this call needs
What to do
Mint a token carrying publisher:manage or provider_publishing:write as appropriate. Scopes are chosen when a token is created and cannot be added afterwards
401 UNAUTHORIZEDon any call
Cause
No credential was sent, or the one sent has expired or been revoked
What to do
Sign in again, or replace the token. Every publishing call needs an authenticated caller — none of them is public
404 NOT_FOUNDon a version submit or a submissions list
Cause
Nothing has ever published under that provider id, so there is no catalog entry to add a version to or to list submissions for
What to do
Check the id, including the namespace prefix. If this really is the provider's first version, use the new-provider call instead
404 NOT_FOUNDon a submission read or a withdraw
Cause
The submission id is wrong, or belongs to a submission that no longer exists
What to do
Take the id from the response the submit call gave you, or from the provider's submission list
404 NOT_FOUNDon deprecate or restore
Cause
The provider id is unknown, or that version never published
What to do
Check both parts of the path. Only a published version has a lifecycle; a submission still in flight has a state instead
The submission sat in submitted for days
Cause
It is at the verified tier and is waiting for a human reviewer
What to do
Nothing to do from your side. Check the contact address on your publisher profile is one you read, since that is where a reviewer's questions go. If you meant to publish without a review, withdraw it and resubmit at community
The submission ended in changes_requested
Cause
A reviewer asked for something to change
What to do
Read the notes on the submission, fix the manifest, and submit again. The version number is free the moment changes are requested, so you can reuse it
The submission ended in verification_failed
Cause
The digest you attested did not resolve at your registry, or the image is not pullable without credentials
What to do
Confirm that pulling the image by digest works from outside your network, then submit a new submission with a digest read from the registry itself
The submission ended in mirror_failed
Cause
The copy-and-sign step could not complete — usually the image disappeared from your registry, or its pushed digest did not match what you attested
What to do
Re-push the image, confirm the digest, and submit again. Deleting or re-tagging the source image between submitting and approval is the common cause
A consumer's pipeline reports an image digest mismatch
Cause
The bytes behind the reference moved after the version published
What to do
Publish a new version. A published version is pinned to a digest on purpose, so replacing bytes behind a tag is never picked up
Consumers see a warning when a pipeline uses a deprecated version
Cause
You deprecated that version, and validating a pipeline that names it now warns
What to do
Expected, and non-blocking. Publish the replacement version and point consumers at it; the warning is what nudges them across
A community provider is published but an organisation cannot install it
Cause
Organisations do not accept the community tier until somebody there turns it on
What to do
Ask an Owner there to accept community providers in the organisation's provider policy. Verifying your namespace also helps, since a policy set to verified publishers only will admit you once the badge is there
A private provider is invisible to the people you expected
Cause
A private provider belongs to the one top-level group you named at submission, and nobody outside it sees it
What to do
Check you named the right group. To reach a second organisation, publish at community instead — a provider's tier and owner cannot be changed after its first version publishes

FAQ

Can I change my namespace?

No. It prefixes every provider id you have ever shipped, so changing it would break every pipeline pinned to one of them. Register a second publisher from a different identity if you need a different namespace.

Can I edit a version after it publishes?

No. A published version is immutable, including its release notes. Publish a new version; deprecate the old one if you want people to move.

Can I rename the provider, or change what a connection to it needs?

No. The provider's name, description and connection shape are taken from the first version that publishes, and a later version's provider block is ignored. If the credentials your provider needs genuinely change, get in touch rather than shipping a version that silently keeps the old shape.

Does deprecating a version break running pipelines?

No. A deprecated version still resolves and still runs. Validating a pipeline that names it raises a non-blocking warning, and the version shows as deprecated wherever versions are listed.

Can a service account publish?

Yes, and for anything automated it should. A publisher binds to whichever identity registered it, so a release pipeline that publishes needs its own publisher, registered from its own service account. That is two scopes, not one: publisher:manage on the token that registers the publisher, and provider_publishing:write on the token that submits.

Why does my image reference disappear from the published capability?

Only at the verified tier, and only because we publish our own signed copy. Your original reference is kept alongside it for the record. At community and private the published reference is yours, untouched.

Do I have to verify my namespace?

Only for the verified tier. Verification is also what lights the badge that an organisation running a verified-publishers-only policy is looking for, so it widens who can install what you ship even at the community tier.

  • Using providersinstalling a provider into a group, connecting credentials to it, and pinning a version in a pipeline
  • Provider policy and administrationhow an organisation decides which tiers it accepts, and what platform staff can do to a published provider
  • Providerswhere the provider model starts, if you landed here before deciding to publish
  • Pipelineshow a capability you publish is wired into a pipeline and run
  • Access tokensminting a token with the publishing scopes, and what a service account token can carry
  • Service accountsthe identity a release pipeline registers its own publisher from