slashevents.xyz

RPC endpoint for agent account, project, user, and event operations.

Endpoint: /rpc

Auth

Type: Application-layer certificate signatures

Public methods: createUser

All RPC methods except createUser require a registered certificate fingerprint and a request signature made with the matching private key.

Create Certificate

Create a local P-256 self-signed certificate for the agent. The private key never leaves the agent.

openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -keyout client.key -out client.pem -days 365 -nodes -subj "/CN=agent-name"
openssl x509 -in client.pem -noout -fingerprint -sha256
Store in 1Password

Store the generated key, public certificate, and fingerprint in a named 1Password item so humans and agents can discover them later.

OP_VAULT="Private"
SLASHEVENTS_ALIAS="agent-name"
SLASHEVENTS_FINGERPRINT="$(openssl x509 -in client.pem -noout -fingerprint -sha256 | cut -d= -f2)"

op item create \
  --category "Secure Note" \
  --vault "$OP_VAULT" \
  --title "slashevents agent ${SLASHEVENTS_ALIAS}" \
  --tags "slashevents,agent" \
  "client.key[file]=./client.key" \
  "client.pem[file]=./client.pem" \
  "fingerprint[text]=${SLASHEVENTS_FINGERPRINT}"
Store in Apple Keychain

Import the certificate and private key as a non-exportable Keychain identity. Store the fingerprint separately for easy CLI lookup.

SLASHEVENTS_ALIAS="agent-name"
SLASHEVENTS_FINGERPRINT="$(openssl x509 -in client.pem -noout -fingerprint -sha256 | cut -d= -f2)"
P12="$(mktemp -t slashevents-agent.XXXXXX.p12)"

openssl pkcs12 -export \
  -inkey ./client.key \
  -in ./client.pem \
  -name "slashevents agent ${SLASHEVENTS_ALIAS}" \
  -out "$P12"

security import "$P12" \
  -k "$HOME/Library/Keychains/login.keychain-db" \
  -f pkcs12 \
  -x

security add-generic-password \
  -a "$SLASHEVENTS_ALIAS" \
  -s "slashevents fingerprint" \
  -l "slashevents agent ${SLASHEVENTS_ALIAS} fingerprint" \
  -w "$SLASHEVENTS_FINGERPRINT" \
  -U

rm -f "$P12"

Sign Up

Register an agent identity with its alias and public certificate.

curl https://slashevents.xyz/rpc \
  -H 'Content-Type: application/json' \
  -d "$(jq -n --rawfile cert client.pem '{method:"createUser", params:{alias:"agent-name", publicCertPem:$cert}}')"

Authenticated Request

Sign each authenticated request. The signed payload is METHOD, path with query, timestamp, and SHA-256 hex of the exact request body, joined with newline characters.

body='{"method":"getProjects","params":{}}'
fingerprint="$(openssl x509 -in client.pem -noout -fingerprint -sha256 | cut -d= -f2)"
timestamp="$(date +%s)"
body_sha256="$(printf '%s' "$body" | openssl dgst -sha256 -hex | awk '{print $2}')"
signing_string="$(printf 'POST\n/rpc\n%s\n%s' "$timestamp" "$body_sha256")"
signature="$(printf '%s' "$signing_string" | openssl dgst -sha256 -sign client.key | openssl base64 -A)"

curl https://slashevents.xyz/rpc \
  -H "X-SlashEvents-Fingerprint: $fingerprint" \
  -H "X-SlashEvents-Timestamp: $timestamp" \
  -H "X-SlashEvents-Signature: $signature" \
  -H 'Content-Type: application/json' \
  -d "$body"
Authenticate with 1Password

Retrieve the key and certificate into a temporary directory, sign the request, and remove the temporary files when the shell exits.

OP_VAULT="Private"
SLASHEVENTS_ALIAS="agent-name"
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT

op read --out-file "$tmpdir/client.key" "op://${OP_VAULT}/slashevents agent ${SLASHEVENTS_ALIAS}/client.key"
op read --out-file "$tmpdir/client.pem" "op://${OP_VAULT}/slashevents agent ${SLASHEVENTS_ALIAS}/client.pem"
chmod 600 "$tmpdir/client.key" "$tmpdir/client.pem"

body='{"method":"getProjects","params":{}}'
fingerprint="$(openssl x509 -in "$tmpdir/client.pem" -noout -fingerprint -sha256 | cut -d= -f2)"
timestamp="$(date +%s)"
body_sha256="$(printf '%s' "$body" | openssl dgst -sha256 -hex | awk '{print $2}')"
signing_string="$(printf 'POST\n/rpc\n%s\n%s' "$timestamp" "$body_sha256")"
signature="$(printf '%s' "$signing_string" | openssl dgst -sha256 -sign "$tmpdir/client.key" | openssl base64 -A)"

curl https://slashevents.xyz/rpc \
  -H "X-SlashEvents-Fingerprint: $fingerprint" \
  -H "X-SlashEvents-Timestamp: $timestamp" \
  -H "X-SlashEvents-Signature: $signature" \
  -H 'Content-Type: application/json' \
  -d "$body"
Authenticate with Apple Keychain

Use Keychain to discover the stored identity and fingerprint. Native macOS agents should sign with the Keychain identity through Security.framework instead of exporting the private key.

SLASHEVENTS_ALIAS="agent-name"

security find-identity -v -p ssl-client "$HOME/Library/Keychains/login.keychain-db" \
  | grep "slashevents agent ${SLASHEVENTS_ALIAS}"

security find-generic-password \
  -a "$SLASHEVENTS_ALIAS" \
  -s "slashevents fingerprint" \
  -w

Transport

Request

{
  "id": "optional request id",
  "method": "method name",
  "params": {}
}

Success

{
  "id": "optional request id",
  "messages": [
    {
      "id": "01900000-0000-7000-8000-000000000000",
      "payload": "operator-facing message"
    }
  ],
  "result": {}
}

Error

{
  "id": "optional request id",
  "messages": [
    {
      "id": "01900000-0000-7000-8000-000000000000",
      "payload": "operator-facing message"
    }
  ],
  "error": {
    "code": "ERROR_CODE",
    "hint": "optional human-readable hint"
  }
}

Every RPC response includes a top-level messages array. Each message has a UUIDv7 id and string payload. Agents should log non-empty messages, flag them for human review, then acknowledge them with ackMessages. Responses return a bounded message batch; if more messages are waiting, the batch includes an acknowledgeable overflow message telling the agent to request again after acknowledgement.

Billing

Projects are prepaid. Call getProjectBilling for the project deposit address, chain, token, balance, event price, and low-balance threshold. Ingress returns PAYMENT_REQUIRED when the project balance cannot cover another event.

Low-balance notices are returned through the response messages array. Agents should surface those notices to a human and acknowledge them with ackMessages after they have been handled.

Rate Limits

Authenticated RPC methods are rate-limited per agent. Public signup and malformed RPC requests are rate-limited per source IP. Rate-limited RPC calls return RATE_LIMIT_EXCEEDED with a retry hint.

Methods

ackMessages

Params

NameTypeRequiredValues
messageIds string/uuidv7[] yes

Returns

NameTypeRequiredValues
ok boolean yes
addUserToProject

Params

NameTypeRequiredValues
projectId string/uuidv7 yes
userId string/uuidv7 yes
permissions string/enum[] yes PROJECT_MANAGE_USERS, PROJECT_READ_USERS, PROJECT_READ_EVENTS

Returns

NameTypeRequiredValues
ok boolean yes
createProject

Params

NameTypeRequiredValues
name string yes

Returns

NameTypeRequiredValues
projectId string/uuidv7 yes
createUser

Params

NameTypeRequiredValues
alias string yes
publicCertPem string yes

Returns

NameTypeRequiredValues
user object yes
user.id string/uuidv7 yes
user.alias string yes
user.fingerprintSha256 string yes
user.subject string | null yes
user.certValidFrom string | null yes
user.certValidTo string | null yes
user.createdAt string yes
user.revoked boolean yes
user.revokedAt string | null yes
getEvents

Params

NameTypeRequiredValues
projectId string/uuidv7 yes
type string/enum no WEBHOOK_RECEIVED, PROJECT_CREATED, PROJECT_USER_ADDED, PROJECT_USER_REMOVED, PROJECT_USER_PERMISSION_GRANTED, PROJECT_USER_PERMISSION_REVOKED
limit integer no
cursor string no
longPollDurationSeconds integer no

Returns

NameTypeRequiredValues
events object[] yes
events[].id string/uuidv7 yes
events[].projectId string/uuidv7 yes
events[].type string/enum yes WEBHOOK_RECEIVED, PROJECT_CREATED, PROJECT_USER_ADDED, PROJECT_USER_REMOVED, PROJECT_USER_PERMISSION_GRANTED, PROJECT_USER_PERMISSION_REVOKED
events[].data unknown yes
events[].receivedAt string yes
events[].actorName string | null yes
nextCursor string | null yes
hasMore boolean yes
getProject

Params

NameTypeRequiredValues
projectId string/uuidv7 yes

Returns

NameTypeRequiredValues
project object yes
project.id string/uuidv7 yes
project.name string yes
project.createdAt string yes
project.webhookPathAllowlist string[] yes
project.retentionConfig object yes
project.retentionConfig.durationSeconds integer | null yes
project.retentionConfig.maxEvents integer | null yes
getProjectBilling

Returns the project billing deposit address, token details, balance, and global billing thresholds.

Params

NameTypeRequiredValues
projectId string/uuidv7 yes

Returns

NameTypeRequiredValues
billing object yes
billing.depositAddress string yes
billing.chainId integer yes
billing.tokenAddress string yes
billing.tokenSymbol string yes
billing.tokenDecimals integer yes
billing.balanceAtomic string yes
billing.eventPriceAtomic string yes
billing.lowBalanceThresholdAtomic string yes
getProjectRetentionConfig

Params

NameTypeRequiredValues
projectId string/uuidv7 yes

Returns

NameTypeRequiredValues
retentionConfig object yes
retentionConfig.durationSeconds integer | null yes
retentionConfig.maxEvents integer | null yes
getProjects

Params

NameTypeRequiredValues
cursor string/uuidv7 no
limit integer no

Returns

NameTypeRequiredValues
projects object[] yes
projects[].id string/uuidv7 yes
projects[].name string yes
projects[].createdAt string yes
nextCursor string/uuidv7 no
getProjectUsers

Params

NameTypeRequiredValues
projectId string/uuidv7 yes
cursor string/uuidv7 no
limit integer no

Returns

NameTypeRequiredValues
users object[] yes
users[].userId string/uuidv7 yes
users[].displayName string yes
users[].permissions string/enum[] yes PROJECT_MANAGE_USERS, PROJECT_READ_USERS, PROJECT_READ_EVENTS
nextCursor string/uuidv7 no
getProjectWebhookPathAllowlist

Returns the project's webhook ingress allowlist as full-match regular expression path patterns.

Params

NameTypeRequiredValues
projectId string/uuidv7 yes

Returns

NameTypeRequiredValues
webhookPathAllowlist string[] yes
removeEvent

Params

NameTypeRequiredValues
projectId string/uuidv7 yes
eventId string/uuidv7 yes

Returns

NameTypeRequiredValues
ok boolean yes
removeUserFromProject

Params

NameTypeRequiredValues
projectId string/uuidv7 yes
userId string/uuidv7 yes

Returns

NameTypeRequiredValues
ok boolean yes
setProjectRetentionConfig

Params

NameTypeRequiredValues
projectId string/uuidv7 yes
retentionConfig object yes
retentionConfig.durationSeconds integer | null yes
retentionConfig.maxEvents integer | null yes

Returns

NameTypeRequiredValues
retentionConfig object yes
retentionConfig.durationSeconds integer | null yes
retentionConfig.maxEvents integer | null yes
setProjectWebhookPathAllowlist

Sets the project's webhook ingress allowlist. paths entries are full-match regular expression patterns evaluated against the path after /ingress/{projectId}. Literal paths such as /stripe/hooks work; use patterns such as /customers/[^/]+/events for paths with IDs.

Params

NameTypeRequiredValues
projectId string/uuidv7 yes
paths string[] yes

Returns

NameTypeRequiredValues
webhookPathAllowlist string[] yes
updateProjectUserPermissions

Params

NameTypeRequiredValues
projectId string/uuidv7 yes
userId string/uuidv7 yes
permissions string/enum[] yes PROJECT_MANAGE_USERS, PROJECT_READ_USERS, PROJECT_READ_EVENTS

Returns

NameTypeRequiredValues
ok boolean yes