Vadyl exposes every entity through gRPC with proto contracts compiled from the canonical entity model. Server reflection is enabled — clients can discover service shape at runtime.

Endpoint

grpc://api.vadyl.app:443
# or self-hosted gRPC port

Generated proto

For an entity Order:

syntax = "proto3";

package vadyl.app.v1;

service OrderService {
  rpc Get    (GetOrderRequest)    returns (Order);
  rpc List   (ListOrderRequest)   returns (ListOrderResponse);
  rpc Create (CreateOrderRequest) returns (Order);
  rpc Update (UpdateOrderRequest) returns (Order);
  rpc Delete (DeleteOrderRequest) returns (DeleteResult);

  // Streaming change events
  rpc Watch  (WatchOrderRequest)  returns (stream OrderEvent);
}

message Order {
  string id = 1;
  string total = 2;     // decimal as string
  string currency = 3;
  OrderStatus status = 4;
  string customer_id = 5;
  google.protobuf.Timestamp created_at = 6;
}

enum OrderStatus {
  ORDER_STATUS_UNSPECIFIED = 0;
  ORDER_STATUS_PENDING     = 1;
  ORDER_STATUS_PAID        = 2;
  ORDER_STATUS_FULFILLED   = 3;
  ORDER_STATUS_REFUNDED    = 4;
}

Authentication

Bearer tokens via metadata, in any language:

import { createGrpcTransport } from "@connectrpc/connect-node";
import { createClient } from "@connectrpc/connect";
import { OrderService } from "./vadyl_app_v1/order_pb_connect";


const transport = createGrpcTransport({
  baseUrl: "https://api.vadyl.app",
  interceptors: [(next) => async (req) => {
    req.header.set("authorization", `Bearer ${process.env.VADYL_TOKEN}`);
    req.header.set("x-vadyl-tenant", "acme");
    req.header.set("x-vadyl-project", "billing");
    return next(req);
  }],
});
const orders = createClient(OrderService, transport);

Calling unary RPCs

// rpc List(ListOrderRequest) returns (ListOrderResponse)
ListOrderResponse resp = stub.List(ListOrderRequest.newBuilder()
    .setFilter(OrderFilter.newBuilder()
        .addAllStatus(List.of(OrderStatus.ORDER_STATUS_PAID))
        .setTotal(NumericFilter.newBuilder().setGt("100")))
    .addSort(Sort.newBuilder().setField("createdAt").setDirection(SORT_DESC))
    .setPageSize(50)
    .addInclude("customer")
    .build());

Streaming change events

// rpc Watch(WatchOrderRequest) returns (stream OrderEvent)

Error model

Errors use standard gRPC status codes plus typed details:

Status code: PERMISSION_DENIED
Message:     Access denied for read on Order
Details:
  - vadyl.app.v1.ErrorDetail
      code:          "ACCESS_DENIED"
      reason_code:   "Access.DeniedByMissingClaim"
      correlation_id:"01HXY..."

Reflection

Server reflection is enabled out of the box. Discover services with grpcurl:

grpcurl api.vadyl.app:443 list
grpcurl api.vadyl.app:443 describe vadyl.app.v1.OrderService

Pull the proto

# Download the proto bundle
curl https://api.vadyl.app/grpc/proto/vadyl-app.proto > vadyl.proto

# Generate clients yourself
protoc --go_out=. --go-grpc_out=. vadyl.proto
protoc --plugin=protoc-gen-ts_proto --ts_proto_out=. vadyl.proto