On this page
Get started
Quick start
Connect your app to Shipbell: create a project, add a signing key, sign tokens on your backend and add the widget or ShipbellKit.
1. Create a projectComing soon
Sign in to the admin at https://app.shipbell.app and create a project for your product. The project gets a board at https://<slug>.shipbell.app and a public id that starts with prj_.
2. Copy your publishable keyComing soon
In the project's settings, copy the publishable key. It starts with sb_pk_live_, identifies your project and goes into your web and iOS apps. API keys explains both kinds of key.
3. Add a signing keyComing soon
Create a signing key in the project's settings. The admin makes the key pair in your browser, shows or downloads the private key once, and sends only the public key to Shipbell. Store the private key and its key id (kid) in your backend's secrets.
4. Sign a token on your backend
Add a route to your backend, such as POST /api/feedback/token, that returns a token for the signed-in user. The token is an ES256 JSON Web Token that lives at most 10 minutes; issue it for 5 minutes. Sign your users in lists every claim.
import { randomBytes } from 'node:crypto';
import { importPKCS8, SignJWT } from 'jose';
const privateKey = await importPKCS8(process.env.FEEDBACK_SSO_PRIVATE_KEY, 'ES256');
export function feedbackToken(user) {
return new SignJWT({ email: user.email, email_verified: user.emailVerified })
.setProtectedHeader({ alg: 'ES256', kid: process.env.FEEDBACK_SSO_KID, typ: 'sb-sso+jwt' })
.setIssuer(process.env.FEEDBACK_PROJECT_ID)
.setAudience('https://api.shipbell.app')
.setSubject(user.id)
.setIssuedAt()
.setExpirationTime('5m')
.setJti(randomBytes(16).toString('base64url'))
.sign(privateKey);
}5. Add the widget or ShipbellKitComing soon
Both call your token route when they need to sign in, and trade the token for a Shipbell session. See Web widget and iOS (ShipbellKit).
import { createFeedback } from '@shipbell/widget';
const feedback = createFeedback({ projectKey: 'sb_pk_live_…', apiOrigin: 'https://api.shipbell.app' });
feedback.identify({
getToken: async () => {
const response = await fetch('/api/feedback/token', { method: 'POST' });
return (await response.json()).token;
}
});
feedback.open();
feedback.openBoard('/');
feedback.openBoard('/roadmap');
feedback.openBoard('/me/reports');ShipbellKit.configure(
projectKey: "sb_pk_live_…",
host: URL(string: "https://api.shipbell.app")!,
tokenProvider: { try await auth.feedbackToken() },
context: { await FeedbackContext.current() }
)
ShipbellKit.setUser(userID)
view.feedbackSheet(isPresented: $show)
ShipbellKit.openBoard(.ideas)6. Check that the API answers
The version endpoint needs no key. It answers {"version": "…"} with the commit SHA of the running release. See Get the running version.
curl https://api.shipbell.app/v1/versionconst response = await fetch('https://api.shipbell.app/v1/version');
const data = await response.json();let url = URL(string: "https://api.shipbell.app/v1/version")!
let (data, response) = try await URLSession.shared.data(from: url)