Cariosan

Backend integration (any language)

Cariosan is plain REST. Wire it from Node, Python, PHP, Ruby, Java, .NET, Bash — anything with an HTTP client.

6 min readUpdated May 14, 2026

Cariosan ships official SDKs for Go (cariosan-go) and TypeScript (@cariosan/client), but you don't have to use them. The wire surface is plain REST + WebSocket. Any backend that can speak HTTP can integrate.

This page shows you the minimum integration in five popular backends so you can copy and adapt.

What your backend needs to do

In the typical Cariosan setup, your backend has exactly one job: issue a short-lived user JWT to your frontend, signed with your workspace's api_secret. The frontend talks directly to Cariosan after that.

┌─────────────┐    ┌──────────────────┐    ┌─────────────┐
│  Browser /  │ ←→ │  Your backend    │ ←→ │  Cariosan   │
│  Mobile app │    │  (1 endpoint)    │    │  REST API   │
└─────┬───────┘    └──────────────────┘    └─────────────┘
      │                                           ▲
      └────────── WebSocket (with JWT) ───────────┘

Each request your backend makes to Cariosan:

POST /v1/auth/token HTTP/1.1
Host: api.cariosan.com
Authorization: Bearer pk_live_…:sk_live_…
Content-Type: application/json

{"user_id": "your-internal-user-id"}

The response:

{ "token": "eyJhbGciOiJIUzI1NiI..." }

Hand that token to your frontend. That's it.

Keep api_secret on the server

The sk_* secret must never reach a browser. Storing it in env vars on your server is the standard pattern. If it leaks, rotate it.

Examples

The flow in every backend is the same: upsert the user → issue JWT → return to frontend. Only the syntax changes.

Node.js (Express + built-in fetch)

server.js
import express from 'express'
 
const app = express()
app.use(express.json())
 
const AUTH = `Bearer ${process.env.CARIOSAN_API_KEY}:${process.env.CARIOSAN_API_SECRET}`
const HEADERS = { Authorization: AUTH, 'Content-Type': 'application/json' }
 
app.post('/api/cariosan-token', async (req, res) => {
  const user = req.user           // pulled from your existing auth middleware
  if (!user) return res.status(401).end()
 
  // 1. Upsert the user in Cariosan.
  await fetch('https://api.cariosan.com/v1/users', {
    method: 'POST',
    headers: HEADERS,
    body: JSON.stringify({ external_id: user.id, name: user.name }),
  })
 
  // 2. Issue a JWT scoped to that user.
  const resp = await fetch('https://api.cariosan.com/v1/auth/token', {
    method: 'POST',
    headers: HEADERS,
    body: JSON.stringify({ user_id: user.id }),
  })
  const { token } = await resp.json()
  res.json({ token })
})
 
app.listen(3000)

Python (Flask + requests)

import os
from flask import Flask, jsonify, request
import requests

app = Flask(__name__)

AUTH = (os.environ['CARIOSAN_API_KEY'], os.environ['CARIOSAN_API_SECRET'])

@app.post('/api/cariosan-token')
def cariosan_token():
    user = current_user()        # your auth helper
    if not user:
        return '', 401

    requests.post(
        'https://api.cariosan.com/v1/users',
        auth=AUTH,
        json={'external_id': user.id, 'name': user.name},
    )

    resp = requests.post(
        'https://api.cariosan.com/v1/auth/token',
        auth=AUTH,
        json={'user_id': user.id},
    )
    return jsonify(token=resp.json()['token'])

PHP (Laravel)

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Route;

Route::post('/cariosan-token', function () {
    $user = auth()->user();
    if (! $user) {
        return response('', 401);
    }

    $auth = [
        'Authorization' => 'Bearer '.env('CARIOSAN_API_KEY').':'.env('CARIOSAN_API_SECRET'),
    ];

    Http::withHeaders($auth)->post('https://api.cariosan.com/v1/users', [
        'external_id' => $user->id,
        'name' => $user->name,
    ]);

    $resp = Http::withHeaders($auth)->post('https://api.cariosan.com/v1/auth/token', [
        'user_id' => $user->id,
    ]);

    return response()->json(['token' => $resp->json('token')]);
})->middleware('auth');

Ruby (Rails)

class CariosanController < ApplicationController
  before_action :authenticate_user!

  def token
    auth = "Bearer #{ENV['CARIOSAN_API_KEY']}:#{ENV['CARIOSAN_API_SECRET']}"
    headers = { 'Authorization' => auth, 'Content-Type' => 'application/json' }

    HTTParty.post(
      'https://api.cariosan.com/v1/users',
      headers: headers,
      body: { external_id: current_user.id, name: current_user.name }.to_json,
    )

    resp = HTTParty.post(
      'https://api.cariosan.com/v1/auth/token',
      headers: headers,
      body: { user_id: current_user.id }.to_json,
    )

    render json: { token: resp.parsed_response['token'] }
  end
end

Bash (curl, for quick CI / scripting)

terminal
AUTH="Bearer $CARIOSAN_API_KEY:$CARIOSAN_API_SECRET"
USER_ID="alice"
 
# 1. Upsert
curl -X POST https://api.cariosan.com/v1/users \
  -H "Authorization: $AUTH" -H 'Content-Type: application/json' \
  -d "{\"external_id\":\"$USER_ID\",\"name\":\"Alice\"}"
 
# 2. Issue JWT
curl -X POST https://api.cariosan.com/v1/auth/token \
  -H "Authorization: $AUTH" -H 'Content-Type: application/json' \
  -d "{\"user_id\":\"$USER_ID\"}"

When to use an official SDK

The official SDKs (cariosan-go, @cariosan/client) give you typed responses, automatic retries, and convenience methods for non-JWT operations (uploading attachments, building channel queries). If your backend is already in Go or TypeScript, the SDK is the easier path.

For everything else, raw HTTP is fully supported and never going to go away. The REST surface is documented in the API reference.

Optional: webhooks

If you want to react to events (a new message arrived, a channel was created, a user joined), point Cariosan at a URL on your backend and verify the X-Cariosan-Signature header. See Webhooks guide.

This is also language-agnostic: the signature is HMAC-SHA256 of the raw body using your api_secret as the key.

Optional: server-side operations

Anything you can do via the SDK, you can do via raw HTTP:

  • Create channels: POST /v1/channels
  • Add/remove members: POST /v1/channels/{id}/members
  • Send system messages: POST /v1/messages with system: true
  • Generate presigned attachment URLs: POST /v1/attachments/presign

Browse the full surface in the API reference.

Minimum-viable backend without any framework

If you don't have a backend yet and don't want to spin up Express / Flask / Rails just for this, use a serverless function:

  • Vercel / Netlify functions — single .js or .ts file, deploys with git push.
  • Cloudflare Workers — same shape, runs at the edge.
  • AWS Lambda + API Gateway — slightly more setup but free tier is generous.

The Node example above is a complete Vercel function with no edits needed (just rename to api/cariosan-token.js).

Next steps

Was this page helpful?