Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions src/css/specs.css
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,62 @@ body {
background: url('/img/watermark-ratified.svg');
}

.ipip-historic .watermark {
display: block;
background: url('/img/watermark-historic.svg');
background-color: #faf8f5;
}

.ipip-historic {
--highlight-colour: #b08050;
--highlight-colour-faded: #c9a07a;
--standard-gradient: linear-gradient(to right, #5c4a3a, #b08050);
}

.ipip-historic header {
border-bottom-color: #b08050;
}

.ipip-historic a {
color: #8b6914;
}

.ipip-historic a:hover {
color: #b08050;
}

.ipip-historic h1,
.ipip-historic h2,
.ipip-historic h3,
.ipip-historic h4,
.ipip-historic h5,
.ipip-historic h6 {
color: #5c4a3a;
}

.ipip-historic :is(h2, h3, h4, h5, h6) bdi.secno {
color: #9a8a7a;
}

.ipip-historic pre {
background: #faf6f0;
border-color: #b08050;
}

.ipip-historic div.note,
.ipip-historic div.warning,
.ipip-historic div.example {
background: #faf6f0;
}

.ipip-historic div.note {
border-color: #b08050;
}

.ipip-historic div.warning {
border-color: #c07030;
}

#ipseity-back-to-root {
margin-bottom: 2rem;
background: var(--standard-gradient);
Expand Down
8 changes: 8 additions & 0 deletions src/img/watermark-historic.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
221 changes: 221 additions & 0 deletions src/ipips/ipip-0526.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
---
title: 'IPIP-0526: Historic Bitswap Provider Publishing API'
date: 2025-12-02
ipip: historic
editors:
- name: Marcin Rataj
github: lidel
url: https://lidel.org/
affiliation:
name: Shipyard
url: https://ipshipyard.com
thanks:
- name: Adin Schmahmann
github: aschmahmann
affiliation:
name: Shipyard
url: https://ipshipyard.com
- name: Andrew Gillis
github: gammazero
affiliation:
name: Shipyard
url: https://ipshipyard.com
- name: Henrique Dias
url: https://hacdias.com/
github: hacdias
relatedIssues:
- https://github.com/ipni/index-provider/issues/403
- https://discuss.ipfs.tech/t/19545/9
order: 526
tags: ['ipips']
xref:
- http-routing-v1
---

## Summary

This IPIP documents the `PUT /routing/v1/providers/` HTTP endpoint for publishing signed Bitswap provider records, introduced in 2022 for [index-provider](https://github.com/ipni/index-provider) integration with IPNI.

The API is deprecated because it was never formally specified, lacks conformance tests, has only partial implementation (see notes below), and cannot announce content available via HTTP ([Trustless Gateways](https://specs.ipfs.tech/http-gateways/trustless-gateway/)).

:::warning

This API was never formally specified, and community projects have been reverse-engineering it. This historic IPIP discourages further adoption and is not intended to be merged into :cite[http-routing-v1].

:::

## Motivation

The Delegated Routing V1 HTTP API (:cite[http-routing-v1]) was designed primarily for content discovery via `GET` endpoints. However, the ecosystem also needed a mechanism for peers to publish their provider records to routing servers without relying solely on DHT announcements.

The [index-provider](https://github.com/ipni/index-provider) project (created in 2021) required a way for IPFS nodes (such as Kubo) to advertise their content to indexers (like cid.contact) alongside DHT. This created a parallel discovery mechanism where providers could reach indexing networks without relying exclusively on the distributed hash table.

The provider publishing API was first added to the Reframe protocol in August 2022 ([ipfs/specs#285](https://github.com/ipfs/specs/pull/285), [go-delegated-routing#37](https://github.com/ipfs/go-delegated-routing/pull/37)). In November 2022, the code was refactored to use `/routing/v1` paths, and the `WriteBitswapRecord` schema was introduced. The code was later migrated to [go-libipfs](https://github.com/ipfs/go-libipfs) and then to [boxo](https://github.com/ipfs/boxo).

When [IPIP-337](https://github.com/ipfs/specs/pull/337) introduced the Delegated Routing V1 HTTP API specification in February 2023, write operations were [explicitly excluded](https://github.com/ipfs/specs/pull/370) to reduce scope. [IPIP-378](https://github.com/ipfs/specs/pull/378) was opened to design a modernized, protocol-agnostic replacement that would support announcing multiple CIDs in a single request, but work on it was never completed before Protocol Labs restructuring. As a result, the Bitswap-specific `PUT /routing/v1/providers/` endpoint remained in boxo but was never formally documented.

The API has not seen significant changes since January 2023, when the HTTP method was changed from POST to PUT. It remains in [boxo v0.35.2](https://github.com/ipfs/boxo/tree/v0.35.2/routing/http) but is marked as deprecated, pending replacement by a protocol-agnostic alternative.

Despite being undocumented, community projects such as [Plebbit](https://plebbit.com) have been reverse engineering this API to implement provider publishing. Creating this historic IPIP discourages further adoption of this deprecated API and provides a reference for discussions about its deprecation and replacements.

## Detailed design

This IPIP documents the `PUT /routing/v1/providers/` endpoint as a historical artifact. This specification is self-contained and not intended to be merged into :cite[http-routing-v1].

### `PUT /routing/v1/providers/`

This endpoint allows peers to publish signed provider records announcing which CIDs they can provide.

#### Request Headers

- `Content-Type`: SHOULD be `application/json`.

#### Request Body

```json
{
"Providers": [
{
"Schema": "bitswap",
"Protocol": "transport-bitswap",
"Signature": "<multibase-encoded-signature>",
"Payload": {
"Keys": ["<cid>", ...],
"Timestamp": <unix-milliseconds>,
"AdvisoryTTL": <nanoseconds>,
"ID": "<peer-id>",
"Addrs": ["<multiaddr>", ...]
}
}
]
}
```

Example with concrete values:

```json
{
"Providers": [
{
"Schema": "bitswap",
"Protocol": "transport-bitswap",
"Signature": "mx5kamm5kzxuCnVJtX3K9DEj8gKlFqXil2x/M8zDTozvzowTY6W+HOALQ2LCkTZCEz4H5qizpnHxPM/rVQ7MNBg",
"Payload": {
"Keys": ["bafkreigur6gzxm3ykiol7ywou3iy3obruzs2q7boizj7oznznid34dzc3e"],
"Timestamp": 1725833163372,
"AdvisoryTTL": 86400000000000,
"ID": "12D3KooWEdCRaQTjjgbtBoSMhnguznp7GHhsin8eRDEtgEso6Z1B",
"Addrs": ["/ip4/198.51.100.1/tcp/4001", "/ip4/198.51.100.1/udp/4001/quic-v1"]
}
}
]
}
```

Where:

- `Schema`: MUST be `"bitswap"` for this record type.
- `Protocol`: SHOULD be `"transport-bitswap"`.
- `Signature`: Multibase-encoded (base64) signature of the SHA256 hash of the JSON-serialized `Payload`.
- `Payload`: The signed provider information:
- `Keys`: Array of CIDs (string-encoded CIDv1) that the peer provides.
- `Timestamp`: Unix timestamp in milliseconds when the record was created.
- `AdvisoryTTL`: Suggested time-to-live in nanoseconds (as JSON number).
- `ID`: The provider's Peer ID (string-encoded as Multihash in Base58btc or CIDv1 with libp2p-key codec).
- `Addrs`: Array of multiaddrs where the provider can be reached.

:::note

Implementation detail: At the time of writing this IPIP (2025Q4), [boxo v0.35.2](https://github.com/ipfs/boxo/releases/tag/v0.35.2) enforces `Schema` (must be `"bitswap"`, returns 400 otherwise) and signature verification (returns 403 on failure). However, `Protocol` is not validated - it is stored and echoed in the response. In [index-provider v0.16.0](https://github.com/ipni/index-provider/releases/tag/v0.16.0), `Timestamp` and `AdvisoryTTL` from the request are ignored: the server uses `time.Now()` for record timestamps and returns its own configured `cidTtl` in the response. Only `Keys`, `ID`, and `Addrs` are used for IPNI announcements, making parts of this specification effectively unused in practice.

:::

#### Signature Verification

The server MUST verify the signature before accepting the record:

1. Extract the public key from the `Payload.ID` peer ID.
2. Decode the `Signature` from multibase (base64).
3. Compute SHA256 hash of the `Payload` object serialized as JSON (the exact bytes as sent in the request).
4. Verify the signature against the hash using the extracted public key.

If verification fails, the server MUST respond with `403 Forbidden`.

#### Response Status Codes

- `200` (OK): The provider record was accepted.
- `400` (Bad Request): The request body is malformed or missing required fields.
- `403` (Forbidden): Signature verification failed.
- `422` (Unprocessable Entity): Request does not conform to schema or semantic constraints.

#### Response Body

```json
{
"ProvideResults": [
{
"Schema": "bitswap",
"Protocol": "transport-bitswap",
"AdvisoryTTL": 86400000000000
}
]
}
```

Where:

- `Schema`: Echoes `"bitswap"`.
- `Protocol`: Echoes `"transport-bitswap"`.
- `AdvisoryTTL`: Server-computed TTL in nanoseconds indicating how long the record will be cached. Clients SHOULD republish before this TTL expires.

## Design rationale

### Bitswap-Specific Schema

The `bitswap` schema was designed specifically for the Bitswap transfer protocol. The schema name and `Protocol` field make it explicit that these records are for peers providing content over Bitswap.

Historically, this made sense when Bitswap was the only means of retrieving data from IPFS peers. In modern times, many providers use HTTP [Trustless Gateways](https://specs.ipfs.tech/http-gateways/trustless-gateway/) in addition to Bitswap, and sometimes instead of it.

This tight coupling to Bitswap is one of the reasons this API is considered deprecated. Future iterations should support protocol-agnostic provider announcements.

### User benefit

This API provided a convenient way for [index-provider](https://github.com/ipni/index-provider) to enable Kubo users to announce content to IPNI indexers (like cid.contact) without relying solely on DHT.

However, the API was never adopted outside of the IPNI ecosystem, limiting its utility and test coverage in practice.

### Compatibility

This is a legacy API. The existing client/server implementation in [boxo v0.35.2](https://github.com/ipfs/boxo/tree/v0.35.2/routing/http) serves as the historical reference.

The related types (`WriteBitswapRecord`, `WriteBitswapRecordResponse`, `SchemaBitswap`) were marked as deprecated in boxo on August 24, 2023, when they were revived specifically to maintain backwards compatibility with index-provider.

New implementations SHOULD NOT implement this endpoint. Existing deployments MAY continue using it but should plan migration to future protocol-agnostic alternatives.

### Security

- **Authentication**: Provider records are cryptographically signed to prevent unauthorized announcements. Only the peer that owns the private key corresponding to the announced Peer ID can publish records for that identity, preventing malicious actors from advertising content they do not possess.
- **Replay Protection**: The `Timestamp` field was intended to allow servers to reject stale records.
- **TTL Enforcement**: The `AdvisoryTTL` was intended to limit how long records persist.

:::note

As noted earlier, [index-provider v0.16.0](https://github.com/ipni/index-provider/releases/tag/v0.16.0) ignores `Timestamp` and `AdvisoryTTL`, providing no replay protection. This is acceptable for deployments where both client and server are trusted and run in a private network.

:::

### Alternatives

[IPIP-378](https://github.com/ipfs/specs/pull/378) was an attempt to design a modernized, protocol-agnostic replacement that would support announcing multiple CIDs in a single request using signed DAG-CBOR and/or JSON payloads. [ipni/index-provider#403](https://github.com/ipni/index-provider/issues/403) was opened to migrate index-provider to IPIP-378 once ratified, but IPIP-378 was never completed.

At the time of writing this IPIP (2025Q4), there is no vendor-agnostic alternative to this HTTP API. A future IPIP could address this gap by extending [:cite[http-routing-v1]](https://specs.ipfs.tech/routing/http-routing-v1/) with a modern specification for delegated publishing of provider information over HTTP. Such work should incorporate lessons from this historic API and support both Bitswap and HTTP ([Trustless Gateway](https://specs.ipfs.tech/http-gateways/trustless-gateway/)) providers natively.

## Test fixtures

Not applicable. This IPIP documents existing implementation behavior.

The lack of test fixtures and conformance tests is one of the contributing reasons why this API was never part of official `/routing/v1` specification.

## Copyright

Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).