{"id":"d4f825f92fc811df2426370132717ad72399e846df403999cfd7874172e55450","pubkey":"1336a17e161d0e8af2b68ee95ad2a479fc38bef96a17d6127ea02a40d28dd97e","created_at":1775927115,"kind":30817,"tags":[["d","bud-01"],["title","BUD-01: Server requirements and blob retrieval"],["summary","The base every Blossom server implements: the CORS headers, the error reporting, and the GET and HEAD endpoints that serve a blob by its hash."],["s","draft"],["t","blossom"],["t","bud"],["alt","A specification: BUD-01: Server requirements and blob retrieval"],["client","openspecs-import"],["published_at","1708455998"],["proxy","https://github.com/hzrd149/blossom/blob/b5bd2801d1763aa635fc8fea7a76597e0eb18990/buds/01.md","web"],["x","aac0c1c5b0364352494064e2a9da74147e8b1101bcf65f7136ee4d86d1fd4053"]],"content":"# BUD-01\n\n## Server requirements and blob retrieval\n\n`draft` `mandatory`\n\n_All pubkeys MUST be in hex format_\n\n## Cross origin headers\n\nServers MUST set the `Access-Control-Allow-Origin: *` header on all responses to ensure compatibility with applications hosted on other domains.\n\nFor [preflight](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#preflighted_requests) (`OPTIONS`) requests,\nservers MUST also set, at minimum, the `Access-Control-Allow-Headers: Authorization, *` and `Access-Control-Allow-Methods: GET, HEAD, PUT, DELETE` headers.\n\nThe header `Access-Control-Max-Age: 86400` MAY be set to cache the results of a preflight request for 24 hours.\n\n## Error responses\n\nEvery time a server sends an error response (HTTP status codes >=400), it MAY include a human-readable header `X-Reason` that can be displayed to the user.\n\n## Endpoints\n\nAll endpoints MUST be served from the root of the domain (eg. the `/upload` endpoint MUST be accessible from `https://cdn.example.com/upload`, etc). This allows clients to talk to servers interchangeably when uploading or retrieving blobs\n\n## GET /sha256 - Get Blob\n\nThe `GET /<sha256>` endpoint MUST return the contents of the blob in the response body. the `Content-Type` header SHOULD beset to the appropriate MIME-type\n\nThe endpoint MUST accept an optional file extension in the URL. ie. `.pdf`, `.png`, etc\n\nRegardless of the file extension, the server MUST return the MIME type of the blob in the `Content-Type` header. If the\nserver does not know the MIME type of the blob, it MUST default to `application/octet-stream`\n\n### Proxying and Redirection (Optional)\n\nIf the endpoint returns a redirection 3xx status code such as 307 or 308 ([RFC 9110 section\n15.4](https://datatracker.ietf.org/doc/html/rfc9110#name-redirection-3xx)), it MUST redirect to a URL containing the\nsame sha256 hash as the requested blob. This ensures that if a user copies or reuses the redirect URL, it will\ncontain the original sha256 hash.\n\nWhile the final blob may not be served from a Blossom server (e.g. CDN, IPFS, object storage, etc.), the destination\nserver MUST set the `Access-Control-Allow-Origin: *` header on the response to allow cross-origin requests, as well as\nthe `Content-Type` and `Content-Length` headers to ensure the blob can be correctly displayed by clients. Two ways to\nguarantee this are:\n\n1. Proxying the blob through the Blossom server, allowing it to override headers such as `Content-Type`.\n2. Manipulating the redirect URL to include a file extension that matches the blob type, such as `.pdf`, `.png`, etc. If\n   the server is unable to determine the MIME type of the blob, it MUST default to `application/octet-stream` and MAY\n   include a file extension in the URL that reflects the blob type (e.g. `.bin`, `.dat`, etc.).\n\n### Status codes\n\nServers SHOULD use the following status codes for `GET /<sha256>` responses:\n\n| Status Code                 | Meaning                                                                                                      |\n| --------------------------- | ------------------------------------------------------------------------------------------------------------ |\n| `200 OK`                    | The blob exists and is returned in the response body.                                                        |\n| `206 Partial Content`       | The blob exists and the server is fulfilling a valid `Range` request.                                        |\n| `307 Temporary Redirect`    | The blob is temporarily available from another URL containing the same sha256.                               |\n| `308 Permanent Redirect`    | The blob is permanently available from another URL containing the same sha256.                               |\n| `400 Bad Request`           | The sha256 path, optional file extension, or request headers are malformed.                                  |\n| `401 Unauthorized`          | Authorization is required and missing or invalid. See [BUD-11](nostr:naddr1qvzqqqrcvypzqyek59lpv8gw3tetdrhfttf2g70u8zl0j6sh6cf8agp2grfgmkt7qqrxyaty95cnzuvmwmm#endpoint-authorization-requirements). |\n| `403 Forbidden`             | The request is understood but not allowed by server policy.                                                  |\n| `404 Not Found`             | The blob does not exist.                                                                                     |\n| `416 Range Not Satisfiable` | The blob exists but the requested byte range is invalid or outside the blob size.                            |\n| `429 Too Many Requests`     | The client has exceeded a rate limit or quota.                                                               |\n| `503 Service Unavailable`   | The retrieval service is temporarily unavailable.                                                            |\n\n## HEAD /sha256 - Has Blob\n\nThe `HEAD /<sha256>` endpoint SHOULD be identical to the `GET /<sha256>` endpoint except that it MUST NOT return the\nblob in the reponse body per [RFC 7231](https://www.rfc-editor.org/rfc/rfc7231#section-4.3.2)\n\nThe endpoint MUST respond with the same `Content-Type` and `Content-Length` headers as the `GET /<sha256>` endpoint.\n\nThe endpoint MUST accept an optional file extension in the URL similar to the `GET /<sha256>` endpoint. ie. `.pdf`, `.png`, etc\n\n### Status codes\n\nServers SHOULD use the following status codes for `HEAD /<sha256>` responses:\n\n| Status Code               | Meaning                                                                                                      |\n| ------------------------- | ------------------------------------------------------------------------------------------------------------ |\n| `200 OK`                  | The blob exists and the server returns the same metadata headers as `GET /<sha256>` without a response body. |\n| `307 Temporary Redirect`  | The blob is temporarily available from another URL containing the same sha256.                               |\n| `308 Permanent Redirect`  | The blob is permanently available from another URL containing the same sha256.                               |\n| `400 Bad Request`         | The sha256 path, optional file extension, or request headers are malformed.                                  |\n| `401 Unauthorized`        | Authorization is required and missing or invalid. See [BUD-11](nostr:naddr1qvzqqqrcvypzqyek59lpv8gw3tetdrhfttf2g70u8zl0j6sh6cf8agp2grfgmkt7qqrxyaty95cnzuvmwmm#endpoint-authorization-requirements). |\n| `403 Forbidden`           | The request is understood but not allowed by server policy.                                                  |\n| `404 Not Found`           | The blob does not exist.                                                                                     |\n| `429 Too Many Requests`   | The client has exceeded a rate limit or quota.                                                               |\n| `503 Service Unavailable` | The retrieval service is temporarily unavailable.                                                            |\n\n## Range requests\n\nTo better support mobile devices, video files, or low bandwidth connections. servers should support range requests ([RFC 7233 section 3](https://www.rfc-editor.org/rfc/rfc7233#section-3)) on the `GET /<sha256>` endpoint and signal support using the `accept-ranges: bytes` and `content-length` headers on the `HEAD /<sha256>` endpoint\n\nSee [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests) for more details\n\n## Sunset Header (Optional)\n\nServers MAY include the [`Sunset`](https://www.rfc-editor.org/rfc/rfc8594.html) HTTP response header on `GET /<sha256>` and `HEAD /<sha256>` responses to indicate that a blob is expected to become unavailable at a specific time due to server retention, expiration, or automatic deletion policy.\n\nClients SHOULD treat the `Sunset` value as advisory only. It indicates expected future unavailability of the blob resource, but it does not guarantee that the blob will be deleted at that exact time or that it will remain unavailable forever.\n\nClients MUST NOT interpret `Sunset` as a permanent negative cache signal. After the advertised time, the definitive test of whether a blob is still available is to request `GET /<sha256>` or `HEAD /<sha256>` again.\n\nBecause Blossom blobs are addressed by sha256, the same blob MAY become available again at the same path if a server later re-imports, restores, or re-uploads it. Clients MUST NOT assume that a previously observed `Sunset` header means the blob can never reappear.\n\nAfter the `Sunset` time, servers MAY respond according to their own policy, including `404 Not Found`, `410 Gone`, or a redirection response.\n\nExample:\n\n```http\nHTTP/1.1 200 OK\nSunset: Wed, 11 Nov 2026 11:11:11 GMT\n```\n","sig":"f862083325a80c46031398cd0c36626e1063b73920f00293c82cd77c9a1b62fc1a57e53a86092d4b4d4c0ae503cafb391cfbdea809acc8d4d32edf18abbea487"}