read
Reads the public ideas of one product. Nothing else.
Sign your customers in from your own app, post and vote for them from your server, read public data and receive signed webhooks. Every key belongs to one product and does one job.
A ticket call from your backend, with sample values
# 201. The ticket works once and expires in 60 seconds.
POST /api/v1/integrations/<publicProductKey>/tickets
Authorization: Bearer $IVABOARD_HANDOFF_KEY
302 Location: redeemUrl
Your backend vouches for the signed-in customer with a one-time ticket. The browser carries it back, and the portal redeems it.
You save one https sign-in URL in the console. The portal adds a one-time state value to it.
Once the user is signed in to your app, your server calls the tickets endpoint with your handoff key, the state and your own user id.
The portal redeems the ticket and the customer is signed in. No second password, no email loop.
When someone leaves your product, call the sessions revoke endpoint with their user id and their IvaBoard sessions end.
Mint a ticket, with sample values
# Your backend, after the customer signs in to your app.
POST /api/v1/integrations/<publicProductKey>/tickets
Authorization: Bearer $IVABOARD_HANDOFF_KEY
Content-Type: application/json
{
"state": "<the state the portal sent you>",
"externalUserId": "user_4821",
"displayName": "Dana Whitfield"
}
# 201 with the redeem URL and when it expires. Check that it starts with your portal origin.
{
"redeemUrl": "https://ideas.acme.com/p/<publicProductKey>/handoff/return?state=...&ticket=...",
"expiresAt": "2026-10-15T12:00:00.000Z"
}
# Answer the browser with a redirect. Do not log or show the URL.
302 Location: redeemUrl
Sample values. The user id is yours and is the identity. Email is stored only if you turn on Trust email addresses.
A feedback box inside your app, or an "I want this too" button beside a feature. The calls come from your server, for a user who is signed in to your product.
Post an idea and cast a vote for a signed-in user
# Post an idea. Sample values.
POST /api/v1/public/<publicProductKey>/posts
Authorization: Bearer $IVABOARD_WRITE_KEY
Idempotency-Key: 7c1f6b0e-2d4a-4d51-9a53-0e3f2b8c9a10
{
"boardSlug": "ideas",
"title": "Scheduled reports by email",
"member": { "externalUserId": "user_4821" }
}
# Cast and withdraw that member's one vote. The member goes in the body.
PUT /api/v1/public/<publicProductKey>/posts/<postId>/vote
DELETE /api/v1/public/<publicProductKey>/posts/<postId>/vote
Needs a write key and sign-in from your product to be set up. Votes are idempotent by their method.
Show ideas and votes inside your product or your website, from data you do not have to copy.
Read a product's public ideas
# Newest first, one page at a time. Sample values.
curl -H "Authorization: Bearer $IVABOARD_READ_KEY" \
"https://app.ivaboard.com/api/v1/public/<publicProductKey>/posts?limit=20&status=planned"
# Each item: id, slug, title, bodyHtml, boardSlug, status, voteCount, commentCount, createdAt, updatedAt.
# The answer carries nextCursor for the next page.
The key goes in a header, never in the URL.
Each key has one scope and one product, so a leaked key can do one small thing.
Reads the public ideas of one product. Nothing else.
Posts ideas and casts or withdraws votes for your users. Reads nothing.
Mints sign-in tickets and revokes sessions. Reads and writes nothing else.
Each delivery is signed with HMAC-SHA256 over the timestamp and the raw body. Check the signature before you trust the call.
Only what the public portal shows is sent. Nothing for private boards, hidden ideas or internal notes. HTTPS only, up to 10 webhooks per product, retried five times, and the delivery log is kept for 90 days.
A delivery to your endpoint, with sample values
POST /webhooks/ivaboard
x-fh-timestamp: 1760520600
x-fh-signature: v1=<hex HMAC-SHA256 of timestamp + "." + raw body>
x-fh-event-id: evt_sample_8f3a
{
"id": "evt_sample_8f3a",
"type": "post.status_changed",
"occurredAt": "2026-10-15T09:30:00.000Z",
"product": { "publicKey": "pk_sample" },
"data": { "title": "Dark mode for the dashboard", "voteCount": 128 }
}
Answer any 2xx to acknowledge. A redirect is never followed.
Verify a delivery in Node.js
// Use the raw body bytes, before any JSON parsing.
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verify(rawBody, headers, secret) {
const timestamp = headers['x-fh-timestamp'];
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const signed = timestamp + '.' + rawBody;
const expected = 'v1=' + createHmac('sha256', secret).update(signed).digest('hex');
return headers['x-fh-signature'].split(',')
.map((part) => part.trim()).filter((part) => part.startsWith('v1='))
.some((part) => part.length === expected.length
&& timingSafeEqual(Buffer.from(part), Buffer.from(expected)));
}
Checks each v1 value, refuses a timestamp more than 5 minutes off, and compares in constant time.
Drop the roadmap or changelog into a page you already have.
Embed the roadmap or the changelog, with sample values
<iframe
src="https://<your portal address>/embed/<publicProductKey>/roadmap"
title="Product roadmap"></iframe>
<!-- Also: /embed/<publicProductKey>/changelog and /embed/<publicProductKey>/changelog/<entry> -->
Read-only pages in an iframe. No script to load.
All of them. The sign-in handoff, write and read APIs, signed webhooks and embeds are included in every annual and lifetime plan.
No. IvaBoard offers plain HTTPS APIs, signed webhooks and embeds. You can call them from any language without a client library.
No. Keys are for servers. A request that carries a browser cookie next to a key is refused, so a key never ends up in front-end code.
IvaBoard retries a failed delivery up to five more times, starting at 30 seconds and doubling each time. Every retry carries the same event id, so you can ignore repeats.
Pick a plan, and we set up your workspace within one business day. Questions about the API? Write to support@ivaboard.com.
Already a customer? Sign in