Minne's API.
Read meetings from your own systems: a Slack bot, a nightly sync to your wiki, an agent that searches what was decided. Every meeting comes with its summary, its transcript and everyone's real name.
For your organisation's systems
An admin makes a key on the organisation's page. A key reads the meetings members share with the organisation, and nothing else: never anyone's unshared meetings, recordings or voices. Revoke it at any time, and it stops at once.
For a person's assistant
A person connects Claude, or another app, with their own sign-in. It reads their own meetings and their organisation's shared ones, and names who spoke when they say so. Minne in Claude
Start
- As an admin, open your organisation's page, find API, and make a key. It's shown once: keep it on your server, never in a page or an app people download. Organisation
- Send it as Authorization: Bearer, with any call.
- Check that it works: the answer is your organisation and the key's name.
curl -s https://api.useminne.com/v1/me -H "Authorization: Bearer $MINNE_KEY"Recipes
The meetings since Monday, newest first, a page at a time (follow next_cursor until there's none):
curl -s "https://api.useminne.com/v1/meetings?started_after=2026-11-02T00:00:00%2B01:00" -H "Authorization: Bearer $MINNE_KEY"The meetings closest in meaning to a question. Ask it as you'd ask a colleague who was there, with names and specifics: that finds the right meeting far more often than a topic does. Put a time range in started_after and started_before, never in the question.
curl -s -G https://api.useminne.com/v1/search --data-urlencode "q=What did Erik say about the Atlas delay?" -H "Authorization: Bearer $MINNE_KEY"To keep a copy in sync, page through the list once and keep each meeting's updated_at. After that, ask for those updated_since the latest you saw. Once a day, list every id and delete what's no longer there: members can stop sharing a meeting.
The spec and the skill
The reference below is made from the same OpenAPI spec the API is built from, so the two can't drift apart. Give the spec to your tools, or the skill to your agent: it teaches it to list, read and search Minne, with the query advice we measured.
- openapi.json: the OpenAPI 3.1 spec, for your tools and code generators.
- SKILL.md: an Agent Skill for Claude Code and other agents. To install it for Claude Code:
mkdir -p ~/.claude/skills/minne-api && curl -fsSL https://useminne.com/minne-api/SKILL.md -o ~/.claude/skills/minne-api/SKILL.mdReference
Every call, its parameters, its answers and an example, from the spec.
Meetings with everyone's real name, for your own systems and assistants. https://api.useminne.com
- GET /v1/me
- GET /v1/meetings
- GET /v1/meetings/{id}
- GET /v1/meetings/{id}/transcript
- GET /v1/search
- GET /v1/people
- PATCH /v1/people/{id}
- PUT /v1/meetings/{id}/speakers/{speaker}
GET /v1/me
Whose key this is, or who's signed in
The organisation the key reads for, and the key as its admins named it; or the person signed in, which of their people in Minne is them (me: the speaker who's them in their meetings), and their organisation. The call to check a key or a sign-in works.
200The key's organisation.401No key or token, one that isn't Minne's, a key revoked or of an organisation that ended, or a sign-in ended or disconnected.429The key made 600 requests this minute. Wait the secondsRetry-Aftersays.
{
"type": "organisation",
"id": "o_01JC2Q5Z8K3M7N9P1R4T6V8X0Y",
"name": "Nordljus AB",
"key": {
"id": "k_01JC2Q8B0D2F4H6J8K0M2N4P6Q",
"name": "Slack bot",
"created_at": "2026-11-03T10:00:00+00:00"
}
}GET /v1/meetings
List meetings
The meetings shared with the organisation, or a person's own, the newest first by when they started, a page at a time: follow next_cursor until there's none. A page can hold fewer than limit, even none, when there's more to come: it reads at most 1,000 meetings to fill itself. Each meeting has its id, title, times and who shared it; get one with GET /v1/meetings/{id} for its summary.
scopequery · mine | organisation · default mine | Whose meetings. mine, the default: the user's own, every one, those still being sent or summarised too. organisation: those the user's organisation's members shared with them. (An organisation's key always reads its organisation's.) |
limitquery · integer · default 20 | How many meetings on a page, 20 unless given, at most 100. |
cursorquery · string | For the next page, the next_cursor the page before gave. |
started_afterquery · string | Only meetings that started at this time or after, as ISO 8601 with its offset: 2026-11-03T00:00:00+01:00 is the start of 3 November in Stockholm. |
started_beforequery · string | Only meetings that started at this time or before, as ISO 8601 with its offset: 2026-11-09T23:59:59+01:00 is the end of 9 November in Stockholm. |
updated_sincequery · string | For keeping a copy in step: only meetings shared, or changed, at this time or since, the latest updated_at the last sync saw. A meeting changed in that very second comes again, so none is missed. |
200A page of meetings.400A parameter isn't what it should be;errorsays which.401No key or token, one that isn't Minne's, a key revoked or of an organisation that ended, or a sign-in ended or disconnected.429The key made 600 requests this minute. Wait the secondsRetry-Aftersays.
{
"meetings": [
{
"id": "mtg_01JBX5Q7M2A8N4R6T0V2W4Y6Z801M5JHFTFH01KXC4V2P9JNFA54",
"title": "Acme renewal",
"started_at": "2026-11-03T09:00:12Z",
"ended_at": "2026-11-03T09:44:57Z",
"duration": 2685.4,
"language": "en",
"shared_by": "Ada Lindqvist",
"shared_at": "2026-11-03T11:02:40+00:00",
"updated_at": "2026-11-03T11:02:40+00:00"
}
],
"next_cursor": "eyJvcmciOiAib18wMUpDMlE1WjhLM003TjlQMVI0VDZWOFgwWSJ9"
}GET /v1/meetings/{id}
Read a meeting
A shared meeting as it is now: who spoke, and its summary as one Markdown page with everyone's name. A meeting that isn't shared with the organisation (any more) is a 404, the same as one that never was.
id requiredpath · string | A meeting's id, as a list of meetings or a search gives it. |
includequery · clips | clips adds, for each speaker of the user's own meeting, links to a few seconds of their voice, for the user to open and listen to when they aren't sure who it is. The links expire in an hour. |
200The meeting.401No key or token, one that isn't Minne's, a key revoked or of an organisation that ended, or a sign-in ended or disconnected.404No meeting with this id is shared with the organisation now.429The key made 600 requests this minute. Wait the secondsRetry-Aftersays.
{
"id": "mtg_01JBX5Q7M2A8N4R6T0V2W4Y6Z801M5JHFTFH01KXC4V2P9JNFA54",
"title": "Acme renewal",
"started_at": "2026-11-03T09:00:12Z",
"ended_at": "2026-11-03T09:44:57Z",
"duration": 2685.4,
"language": "en",
"shared_by": "Ada Lindqvist",
"shared_at": "2026-11-03T11:02:40+00:00",
"updated_at": "2026-11-03T11:02:40+00:00",
"speakers": [
{
"speaker": "S1",
"name": "Ada Lindqvist",
"talk_time": 1102.0
},
{
"speaker": "S2",
"name": "Peter Larsson",
"talk_time": 811.5
}
],
"summary": "# Acme renewal\n\n2026-11-03 · 45 min · with Ada Lindqvist, Peter Larsson\n\n**Overview.** Acme renews for two years …\n"
}GET /v1/meetings/{id}/transcript
Read a meeting's transcript
What was said, line by line, with each speaker's name and the seconds into the meeting, a page at a time. from and to read one part of it, such as a topic's times from its summary.
id requiredpath · string | A meeting's id, as a list of meetings or a search gives it. |
fromquery · number | Seconds into the meeting to start at, such as a topic's start in the meeting's summary. |
toquery · number | Seconds into the meeting to stop at, such as a topic's end. |
cursorquery · string | The next_cursor of the page before. |
200A page of the transcript, at most about 40,000 characters.400A parameter isn't what it should be;errorsays which.401No key or token, one that isn't Minne's, a key revoked or of an organisation that ended, or a sign-in ended or disconnected.404No meeting with this id is shared with the organisation now.429The key made 600 requests this minute. Wait the secondsRetry-Aftersays.
{
"lines": [
{
"speaker": "Ada Lindqvist",
"start": 12.31,
"end": 15.02,
"text": "Thanks for making the time, Peter."
},
{
"speaker": "Peter Larsson",
"start": 15.4,
"end": 19.8,
"text": "Of course. Shall we start with the renewal?"
}
]
}GET /v1/search
Search meetings by meaning
The meetings closest in meaning to q, best first: a key's organisation's shared ones, or a person's own and their organisation's (scope). Each has up to 3 passages of its summary that matched, as it reads now. Get a meeting's whole summary with GET /v1/meetings/{id}, and what was said with its transcript.
It searches the summaries, in Swedish or English whichever the query is in: what each meeting was about, its topics, what was decided and who does what, and who was there. Not the transcripts' every word.
Ask it a question, as you'd ask a colleague who was there, with the names and specifics you know. Measured on 18 needs, each written several ways (evals/search), the meeting wanted came first:
- 94% of the time for a question: "What did Erik tell the company at the all-hands about the Atlas delay?"
- 78% for a description: "all-hands where Erik explained why Atlas was delayed"
- 56% for a bare topic: "all-hands", which several meetings are
Time goes in the filters, never in the words. "In August" in q made it worse (61%, from 78%), since meaning has no calendar; started_after and started_before are applied before the search, so nothing outside the range is considered and nothing in it is crowded out.
It works least well on a bare code ("KV-1874") among many that look alike: ask what it was about.
scopequery · all | mine | organisation · default all | Whose meetings. all, the default: the user's own and those their organisation's members shared with them. mine: only the user's own. organisation: only the shared ones. (An organisation's key always searches its organisation's.) |
q requiredquery · string | A question about what was said, with the names and specifics you know, up to 1,000 characters. Swedish or English. |
limitquery · integer · default 5 | How many meetings, 5 unless given, at most 20. |
started_afterquery · string | Only meetings that started at this time or after, as ISO 8601 with its offset: 2026-10-19T00:00:00+02:00 is the start of 19 October in Stockholm. For "in the past two weeks", the time two weeks ago. |
started_beforequery · string | Only meetings that started at this time or before, as ISO 8601 with its offset. |
200The closest meetings, best first. None, when nothing shared is about it.400A parameter isn't what it should be;errorsays which.401No key or token, one that isn't Minne's, a key revoked or of an organisation that ended, or a sign-in ended or disconnected.429The key made 600 requests this minute. Wait the secondsRetry-Aftersays.
{
"results": [
{
"meeting": {
"id": "mtg_01JBX5Q7M2A8N4R6T0V2W4Y6Z801M5JHFTFH01KXC4V2P9JNFB1",
"title": "Atlas launch",
"started_at": "2026-10-20T09:00:00Z",
"shared_by": "Ada Lindqvist"
},
"score": 0.62,
"passages": [
{
"title": "Launch date",
"text": "Launch date\nSara Holm said the integration with Fortnox slips.\nOutcome: February.",
"start": 840.0,
"end": 1310.0
}
]
}
]
}GET /v1/people
List one's people
A person's: the people in their own meetings, as they've named them in Minne, by name a page at a time: other names, role, company, which one is them, whether their voice is confirmed, and how many of their meetings each was in. A key can't.
qquery · string | Part of a name, an old name, a role or a company. |
limitquery · integer · default 50 | How many people on a page, 50 unless given, at most 200. |
cursorquery · string | For the next page, the next_cursor the page before gave. |
200Their people, by name.400A parameter isn't what it should be;errorsays which.401No key or token, one that isn't Minne's, a key revoked or of an organisation that ended, or a sign-in ended or disconnected.403Only a person's own app may do this, in their own meetings; an organisation's key reads.429The key made 600 requests this minute. Wait the secondsRetry-Aftersays.
{
"people": [
{
"person_id": "p_01JC2Q5Z8K3M7N9P1R4T6V8X0Y",
"name": "Peter Larsson",
"aliases": [
"Peter"
],
"role": "CEO",
"company": "Acme",
"is_me": false,
"voice_confirmed": true,
"meetings": 4
}
]
}PATCH /v1/people/{id}
Change one of one's people
A person's: one of their people, renamed, or with a role or company, as they'd change them in Minne. A new name keeps the old one among their other names, and every summary that names them reads the new one at once.
id requiredpath · string | The person's id, as their people and a meeting's speakers give it. |
namebody · string | Their name as the user calls them. |
rolebody · string | Their role; empty clears it. |
companybody · string | Their company; empty clears it. |
200The person as they are now.400A parameter isn't what it should be;errorsays which.401No key or token, one that isn't Minne's, a key revoked or of an organisation that ended, or a sign-in ended or disconnected.403Only a person's own app may do this, in their own meetings; an organisation's key reads.404No meeting with this id is shared with the organisation now.429The key made 600 requests this minute. Wait the secondsRetry-Aftersays.
{
"error": "limit is a number from 1 to 100"
}PUT /v1/meetings/{id}/speakers/{speaker}
Say who a speaker is
A person's, in their own meeting: who a speaker is, as they'd say it in Minne. One of their people (person_id), someone new (name, with role and company if known), nobody they know (unknown), or a voice that wasn't part of the meeting (background). It's their own word, as in Minne: the voice is saved, and Minne recognises it in their later meetings. Minne keeps it as said through the app, with its evidence.
id requiredpath · string | A meeting's id, as a list of meetings or a search gives it. |
speaker requiredpath · string | The speaker's place in the meeting, as the meeting's speakers give it, such as S2. |
person_idbody · string | One of the user's people, by the person_id their people or the meeting's speakers give. |
namebody · string | Someone new, by the name the user calls them. |
rolebody · string | Someone new's role, when it's known. |
companybody · string | Someone new's company, when it's known. |
unknownbody · boolean | True when the user says it's nobody they know. |
backgroundbody · boolean | True for a voice nearby that wasn't part of the meeting, such as someone in a café. |
evidencebody · string | Why, briefly: "invited as Peter Larsson, CEO at Acme". |
200The meeting's speakers as they are now, and how many still need naming.400A parameter isn't what it should be;errorsays which.401No key or token, one that isn't Minne's, a key revoked or of an organisation that ended, or a sign-in ended or disconnected.403Only a person's own app may do this, in their own meetings; an organisation's key reads.404No meeting with this id is shared with the organisation now.409The meeting changed while it was saving, or isn't ready.429The key made 600 requests this minute. Wait the secondsRetry-Aftersays.
{
"error": "limit is a number from 1 to 100"
}