Skip to content

Streams

streams is Skippr Cloud’s append-only partitioned log: produce records to topics, consume with consumer groups and offsets, retain data for a configurable period (max 7 days).

Status: Preview — streams protocol clients connect with SASL/OAUTHBEARER (Cloud JWT) to streams.eu-central-1.cloud.skippr.io:9092. Logical topic names only; broker SCRAM is never customer-visible.

Not a work queue. Competing-consumer jobs (visibility timeout, long poll, DLQ) belong to Queue.

Concepts

TermMeaning
TopicNamed durable append log (logical name, e.g. orders)
PartitionOrdered unit inside a topic
ProducerClient that appends records (Produce)
Consumer groupCooperative readers with shared committed offsets
OffsetPosition of a record within a partition
RetentionHow long records remain readable (default 24h, max 7 days)

Access

Bootstrapstreams.eu-central-1.cloud.skippr.io:9092 (TLS)
Protocolstreams protocol (Admin + Produce/Fetch + consumer groups)
AuthSASL/OAUTHBEARER with a Cloud JWT (tenant_id from claims). You never receive broker SCRAM passwords.
TenantFrom JWT claims only
Optional HTTPS AdminThrough Gateway only (JSON). streams protocol produce/consume does not go through the gateway.

Connect streams protocol clients directly to the bootstrap address. Do not use api.cloud.skippr.io as a streams bootstrap.

Token sources

EnvironmentHow to get the JWT
Devskippr user login~/.skippr/credentials.json access_token (set SKIPPR_AUTH_URL=https://auth.cloud.skippr.io)
CISKIPPR_API_KEYPOST /auth/api-key-exchange
ProdWorkload identity → Cloud JWT

Override with SKIPPR_ACCESS_TOKEN when your client’s OAUTHBEARER callback reads from the environment.

There is no skippr streams CLI in Preview — manage topics with your language’s streams protocol client library.

Operations (Preview)

OperationStatusNotes
CreateTopics / DeleteTopics / MetadataSupportedSelf-service topic lifecycle; logical names only; default retention 24h
Produce / FetchSupportedPer-partition order; at-least-once
Consumer groups (FindCoordinator, JoinGroup, SyncGroup, Heartbeat, LeaveGroup, OffsetCommit, OffsetFetch)SupportedLogical group ids
ListOffsetsSupportedEarliest / latest offsets
DescribeConfigs / AlterConfigsSupportedTopic configs; retention.ms max 7 days
ListGroups / DescribeGroupsSupportedTenant-scoped; logical group ids
CreatePartitionsComing soonIncrease partition count
Transactions / exactly-onceNot in Preview

Limits

LimitValue
Retention default24 hours
Retention max7 days
Max record size1 MiB
Topic / group namesLogical only — do not send t. prefixes

Client snippets

Bootstrap and auth are the same for every language:

text
bootstrap.servers=streams.eu-central-1.cloud.skippr.io:9092
security.protocol=SASL_SSL
sasl.mechanism=OAUTHBEARER
# token = ~/.skippr/credentials.json access_token or SKIPPR_ACCESS_TOKEN

Use logical topic names (orders), never t.{tenant}.*.

Java

java
Properties props = new Properties();
props.put(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG,
    "streams.eu-central-1.cloud.skippr.io:9092");
props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SASL_SSL");
props.put(SaslConfigs.SASL_MECHANISM, "OAUTHBEARER");
props.put(SaslConfigs.SASL_OAUTHBEARER_TOKEN_ENDPOINT_URL, ""); // unused — callback supplies JWT
props.put(SaslConfigs.SASL_JAAS_CONFIG,
    "org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule required;");
props.put(SaslConfigs.SASL_LOGIN_CALLBACK_HANDLER_CLASS,
    SkipprOauthBearerCallback.class.getName()); // reads SKIPPR_ACCESS_TOKEN or credentials.json

try (AdminClient admin = AdminClient.create(props)) {
    admin.createTopics(List.of(new NewTopic("orders", 1, (short) 1))).all().get();
}

Spring

java
@Bean
public ProducerFactory<String, String> producerFactory() {
    Map<String, Object> cfg = new HashMap<>();
    cfg.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,
        "streams.eu-central-1.cloud.skippr.io:9092");
    cfg.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SASL_SSL");
    cfg.put(SaslConfigs.SASL_MECHANISM, "OAUTHBEARER");
    cfg.put(SaslConfigs.SASL_JAAS_CONFIG,
        "org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule required;");
    cfg.put(SaslConfigs.SASL_LOGIN_CALLBACK_HANDLER_CLASS,
        SkipprOauthBearerCallback.class.getName());
    cfg.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
    cfg.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
    return new DefaultKafkaProducerFactory<>(cfg);
}

Python

python
import os, json, pathlib
from confluent_kafka import Producer
from confluent_kafka.admin import AdminClient, NewTopic

def token():
    if t := os.environ.get("SKIPPR_ACCESS_TOKEN"):
        return t
    path = pathlib.Path.home() / ".skippr" / "credentials.json"
    return json.loads(path.read_text())["access_token"]

def oauth_cb(_config):
    return token(), 3600_000  # (token, lifetime_ms)

conf = {
    "bootstrap.servers": "streams.eu-central-1.cloud.skippr.io:9092",
    "security.protocol": "SASL_SSL",
    "sasl.mechanisms": "OAUTHBEARER",
    "oauth_cb": oauth_cb,
}
AdminClient(conf).create_topics([NewTopic("orders", num_partitions=1)])
p = Producer(conf)
p.produce("orders", b"hello")
p.flush()

Go

go
mechanism := kafka.OAuthBearerMechanism{
    TokenProvider: func(ctx context.Context) (kafka.OAuthBearerToken, error) {
        tok := os.Getenv("SKIPPR_ACCESS_TOKEN")
        // or read ~/.skippr/credentials.json
        return kafka.OAuthBearerToken{Token: tok}, nil
    },
}
dialer := &kafka.Dialer{
    TLS:           &tls.Config{},
    SASLMechanism: mechanism,
}
conn, err := dialer.DialContext(ctx, "tcp", "streams.eu-central-1.cloud.skippr.io:9092")
// CreateTopic / WriteMessages with logical name "orders"

Node

js
import { Kafka, logLevel } from "kafkajs";
import fs from "fs";
import os from "os";
import path from "path";

function accessToken() {
  if (process.env.SKIPPR_ACCESS_TOKEN) return process.env.SKIPPR_ACCESS_TOKEN;
  const creds = JSON.parse(
    fs.readFileSync(path.join(os.homedir(), ".skippr", "credentials.json"), "utf8"),
  );
  return creds.access_token;
}

const client = new Kafka({
  clientId: "skippr-demo",
  brokers: ["streams.eu-central-1.cloud.skippr.io:9092"],
  ssl: true,
  sasl: {
    mechanism: "oauthbearer",
    oauthBearerProvider: async () => ({ value: accessToken() }),
  },
  logLevel: logLevel.INFO,
});

const admin = client.admin();
await admin.connect();
await admin.createTopics({ topics: [{ topic: "orders", numPartitions: 1 }] });
  • Queue — SQS-shaped work queues
  • Auth — JWT, API keys, refresh
  • Events — bus rules that may target streams or queues
  • Gateway — HTTPS/JSON only (not streams protocol wire)
  • Roadmap