AI Startup Hub
Reference

Catalog API

A gRPC-Web service for submitting, browsing and upvoting listings in the AI Startup Hub catalog. One proto contract, three ways to call it.

gRPC-Web endpoint

All RPCs are served over gRPC-Web on a single HTTP/1.1-and-up endpoint. No separate REST surface.

Base URL
https://aihub.sarmkadan.com
Protocol
gRPC-Web (grpc-web-text / grpc-web+proto)
Service
catalog.CatalogService
Rate limits
Submit: 10/hr · Upvote: 100/hr per IP
Submitregister a new product and receive its dofollow backlink URL
Getfetch a single product by slug
Listpaginated listing, optionally filtered by category
Searchfull-text search across products, paginated
Upvoteincrement a product's upvote count
Note. gRPC-Web requests must go through a client that speaks the gRPC-Web wire format (e.g. @grpc/grpc-web, grpcurl with -protoset/reflection, or a server-side gRPC client proxied through a gateway). Browsers cannot call raw HTTP/2 gRPC directly.

Proto contract

The full catalog.proto definition. Copy this into your project to generate a client.

syntax = "proto3";

option csharp_namespace = "AIBacklinkHub.Shared";

package catalog;

service CatalogService {
  rpc Submit (SubmitRequest) returns (SubmitResponse);
  rpc Get (GetRequest) returns (ProductResponse);
  rpc List (ListRequest) returns (ListResponse);
  rpc Search (SearchRequest) returns (ListResponse);
  rpc Upvote (UpvoteRequest) returns (UpvoteResponse);
}

message SubmitRequest {
  string url = 1;
  string name = 2;
  string description = 3;
  string category = 4;
  repeated string tags = 5;
}

message SubmitResponse {
  string slug = 1;
  string backlink_url = 2;
}

message ProductResponse {
  string id = 1;
  string slug = 2;
  string name = 3;
  string url = 4;
  string description = 5;
  string category = 6;
  repeated string tags = 7;
  int32 upvotes = 8;
  string submitted_at = 9;
}

message ListRequest {
  int32 page = 1;
  int32 page_size = 2;
  string sort_by = 3;
  string category = 4;
}

message GetRequest {
  string slug = 1;
}

message SearchRequest {
  string query = 1;
  int32 page = 2;
  int32 page_size = 3;
}

message ListResponse {
  repeated ProductResponse products = 1;
  int32 total = 2;
}

message UpvoteRequest {
  string slug = 1;
}

message UpvoteResponse {
  int32 upvotes = 1;
}

grpcurl

Quick manual testing against the live service using grpcurl.

List products
# requires server reflection, or -proto ./catalog.proto
grpcurl -d '{"page": 1, "page_size": 20, "sort_by": "upvotes"}' \
  aihub.sarmkadan.com:443 \
  catalog.CatalogService/List
Submit a listing
grpcurl -d '{
  "url": "https://example.com",
  "name": "Example AI Tool",
  "description": "Short pitch for the product",
  "category": "productivity",
  "tags": ["ai", "saas"]
}' \
  aihub.sarmkadan.com:443 \
  catalog.CatalogService/Submit
Upvote
grpcurl -d '{"slug": "example-ai-tool"}' \
  aihub.sarmkadan.com:443 \
  catalog.CatalogService/Upvote

Python (grpcio)

Generate stubs with grpcio-tools, then call the service directly. gRPC-Web endpoints accept plain gRPC over TLS on the same port, so a standard grpcio secure channel works.

Generate stubs
pip install grpcio grpcio-tools
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. catalog.proto
catalog_client.py
import grpc
import catalog_pb2
import catalog_pb2_grpc

# secure channel — the endpoint is served over TLS on :443
creds = grpc.ssl_channel_credentials()
channel = grpc.secure_channel("aihub.sarmkadan.com:443", creds)
stub = catalog_pb2_grpc.CatalogServiceStub(channel)

# List
response = stub.List(catalog_pb2.ListRequest(
    page=1, page_size=20, sort_by="upvotes"
))
for product in response.products:
    print(product.name, product.upvotes)

# Submit
submit = stub.Submit(catalog_pb2.SubmitRequest(
    url="https://example.com",
    name="Example AI Tool",
    description="Short pitch for the product",
    category="productivity",
    tags=["ai", "saas"],
))
print(submit.slug, submit.backlink_url)

# Upvote
stub.Upvote(catalog_pb2.UpvoteRequest(slug=submit.slug))

Node.js (@grpc/grpc-js)

Use @grpc/grpc-js with @grpc/proto-loader for dynamic loading, or generate static TypeScript stubs with ts-proto.

Install
npm install @grpc/grpc-js @grpc/proto-loader
client.js
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');

const packageDef = protoLoader.loadSync('catalog.proto', {
  keepCase: true,
  longs: String,
  enums: String,
  defaults: true,
  oneofs: true,
});
const proto = grpc.loadPackageDefinition(packageDef).catalog;

const client = new proto.CatalogService(
  'aihub.sarmkadan.com:443',
  grpc.credentials.createSsl()
);

// List
client.List({ page: 1, page_size: 20, sort_by: 'upvotes' }, (err, res) => {
  if (err) throw err;
  res.products.forEach(p => console.log(p.name, p.upvotes));
});

// Submit
client.Submit({
  url: 'https://example.com',
  name: 'Example AI Tool',
  description: 'Short pitch for the product',
  category: 'productivity',
  tags: ['ai', 'saas'],
}, (err, res) => {
  if (err) throw err;
  console.log(res.slug, res.backlink_url);
});
Browser clients. In-browser JS cannot use @grpc/grpc-js (it needs Node's HTTP/2 stack). For browsers, generate a client with protoc-gen-grpc-web and call it through @grpc/grpc-web, which speaks the same gRPC-Web protocol this endpoint exposes.