Skip to main content
miro-sdk-patterns Apply production-ready patterns for @mirohq/miro-api client usage.
Use when implementing Miro integrations, refactoring SDK usage,
or establishing coding standards for Miro REST API v2.
Trigger with phrases like "miro SDK patterns", "miro best practices",
"miro code patterns", "miro client wrapper", "miro typescript".
Jump to install Skills Marketplace Discover and explore AI skills built by the community.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Copy promptShow prompt details A direct command skips the review prompt. Inspect the source before running it.
npx skills add https://github.com/jeremylongshore/claude-code-plugins-plus-skills --skill miro-sdk-patternsThe command stays on one line. Scroll horizontally to inspect it before copying.
Prefer a local copy? Download the files currently available to SkillsMP.
Download Zip Downloading... More from this repository Implement user sign-up and sign-in flows with Clerk.
Use when building authentication UI, customizing sign-in experience,
or implementing OAuth social login.
Trigger with phrases like "clerk sign-in", "clerk sign-up",
"clerk login flow", "clerk OAuth", "clerk social login".
Implement session management and middleware with Clerk.
Use when managing user sessions, configuring route protection,
or implementing token refresh and custom JWT templates.
Trigger with phrases like "clerk session", "clerk middleware",
"clerk route protection", "clerk token", "clerk JWT".
Configure enterprise SSO, role-based access control, and organization management.
Use when implementing SSO integration, configuring role-based permissions,
or setting up organization-level controls.
Trigger with phrases like "clerk SSO", "clerk RBAC",
"clerk enterprise", "clerk roles", "clerk permissions", "clerk organizations".
Related occupations SOC
Based on SOC occupation classification
name miro-sdk-patterns description Apply production-ready patterns for @mirohq/miro-api client usage.
Use when implementing Miro integrations, refactoring SDK usage,
or establishing coding standards for Miro REST API v2.
Trigger with phrases like "miro SDK patterns", "miro best practices",
"miro code patterns", "miro client wrapper", "miro typescript".
allowed-tools Read, Write, Edit version 1.6.0 license MIT author Jeremy Longshore <jeremy@intentsolutions.io> tags ["saas","miro","patterns","typescript"] compatibility Designed for Claude Code
Miro SDK Patterns
Overview
Production-ready patterns for the @mirohq/miro-api Node.js client and direct REST API v2 usage. Covers the high-level Miro client (stateful, OAuth-aware) and the low-level MiroApi client (stateless, token-based).
Prerequisites
@mirohq/miro-api installed
TypeScript 5+ project
Understanding of Miro REST API v2 item model
Two Client Modes
import { Miro , MiroApi } from '@mirohq/miro-api' ;
const miro = new Miro ({
clientId : process.env .MIRO_CLIENT_ID !,
clientSecret : process.env .MIRO_CLIENT_SECRET !,
redirectUrl : process.env .MIRO_REDIRECT_URI !,
});
const userApi = await miro.as ('user-id' );
const api = new MiroApi (process.env .MIRO_ACCESS_TOKEN !);
Pattern 1: Type-Safe Board Service
import { MiroApi } from '@mirohq/miro-api' ;
{
: ;
: ;
: ;
: ;
: ;
: ;
}
{
: ;
: | | | | | | | | ;
: < , >;
: { : ; : ; : };
?: { ?: ; ?: };
: ;
: { : ; : };
}
<T> {
: T[];
: ;
: ;
: ;
: ;
?: ;
}
{
( ) {}
( : ): < > {
response = . . (boardId);
response. ;
}
(
: ,
: { ?: ; ?: ; ?: } = {}
): < < >> {
params = ();
(options. ) params. ( , options. );
(options. ) params. ( , (options. ));
(options. ) params. ( , options. );
response = (
,
{ : . () }
);
response. ();
}
( : ): < []> {
: [] = [];
: | ;
{
page = . (boardId, { : , cursor });
items. (...page. );
cursor = page. ;
} (cursor);
items;
}
( ) {
{
: ,
: ,
};
}
}
interface
MiroBoard
id
string
type
'board'
name
string
description
string
createdAt
string
modifiedAt
string
interface
MiroBoardItem
id
string
type
'sticky_note'
'shape'
'card'
'text'
'frame'
'image'
'document'
'embed'
'app_card'
data
Record
string
unknown
position
x
number
y
number
origin
string
geometry
width
number
height
number
createdAt
string
createdBy
id
string
type
string
interface
PaginatedResponse
data
total
number
size
number
offset
number
limit
number
cursor
string
export
class
BoardService
constructor
private api : MiroApi
async
getBoard
boardId
string
Promise
MiroBoard
const
await
this
api
getBoard
return
body
as
unknown
as
MiroBoard
async
listItems
boardId
string
options
type
string
limit
number
cursor
string
Promise
PaginatedResponse
MiroBoardItem
const
new
URLSearchParams
if
type
set
'type'
type
if
limit
set
'limit'
String
limit
if
cursor
set
'cursor'
cursor
const
await
fetch
`https://api.miro.com/v2/boards/${boardId} /items?${params} `
headers
this
authHeaders
return
json
async
getAllItems
boardId
string
Promise
MiroBoardItem
const
items
MiroBoardItem
let
cursor
string
undefined
do
const
await
this
listItems
limit
50
push
data
cursor
while
return
private
authHeaders
return
'Authorization'
`Bearer ${process.env.MIRO_ACCESS_TOKEN} `
'Content-Type'
'application/json'
Pattern 2: Item Factory
type StickyNoteColor = 'light_yellow' | 'light_green' | 'light_blue'
| 'light_pink' | 'gray' | 'light_cyan' | 'light_orange' ;
interface CreateStickyNoteParams {
boardId : string ;
content : string ;
color ?: StickyNoteColor ;
x ?: number ;
y ?: number ;
width ?: number ;
}
interface CreateShapeParams {
boardId : string ;
content : string ;
shape ?: 'rectangle' | 'circle' | 'triangle' | 'rhombus'
| 'round_rectangle' | 'parallelogram' | 'star'
| 'right_arrow' | 'left_arrow' | 'pentagon' | 'hexagon'
| 'octagon' | 'trapezoid' | 'flow_chart_predefined_process'
| 'can' | 'cross' | 'cloud' ;
fillColor ?: string ;
x ?: number ;
y ?: number ;
width ?: number ;
height ?: number ;
}
interface CreateCardParams {
boardId : string ;
title : string ;
description ?: string ;
dueDate ?: string ;
assigneeId ?: string ;
x ?: number ;
y ?: number ;
}
export class ItemFactory {
constructor (private token : string ) {}
async createStickyNote (params : CreateStickyNoteParams ): Promise <MiroBoardItem > {
return this .post (`/v2/boards/${params.boardId} /sticky_notes` , {
data : { content : params.content , shape : 'square' },
style : { fillColor : params.color ?? 'light_yellow' , textAlign : 'center' },
position : { x : params.x ?? 0 , y : params.y ?? 0 },
geometry : { width : params.width ?? 199 },
});
}
async createShape (params : CreateShapeParams ): Promise <MiroBoardItem > {
return this .post (`/v2/boards/${params.boardId} /shapes` , {
data : { content : params.content , shape : params.shape ?? 'round_rectangle' },
style : { fillColor : params.fillColor ?? '#4262ff' , textAlign : 'center' },
position : { x : params.x ?? 0 , y : params.y ?? 0 },
geometry : { width : params.width ?? 200 , height : params.height ?? 100 },
});
}
async createCard (params : CreateCardParams ): Promise <MiroBoardItem > {
return this .post (`/v2/boards/${params.boardId} /cards` , {
data : {
title : params.title ,
description : params.description ,
dueDate : params.dueDate ,
assigneeId : params.assigneeId ,
},
position : { x : params.x ?? 0 , y : params.y ?? 0 },
});
}
private async post (path : string , body : unknown ): Promise <MiroBoardItem > {
const res = await fetch (`https://api.miro.com${path} ` , {
method : 'POST' ,
headers : {
'Authorization' : `Bearer ${this .token} ` ,
'Content-Type' : 'application/json' ,
},
body : JSON .stringify (body),
});
if (!res.ok ) {
const err = await res.json ();
throw new MiroApiError (res.status , err.message ?? 'API request failed' , err.code );
}
return res.json ();
}
}
Pattern 3: Error Handling Wrapper
export class MiroApiError extends Error {
constructor (
public readonly status : number ,
message : string ,
public readonly code ?: string ,
) {
super (message);
this .name = 'MiroApiError' ;
}
get isRetryable (): boolean {
return this .status === 429 || (this .status >= 500 && this .status < 600 );
}
get isAuthError (): boolean {
return this .status === 401 || this .status === 403 ;
}
}
async function safeMiroCall<T>(
operation : () => Promise <T>,
context : string
): Promise <{ data : T | null ; error : MiroApiError | null }> {
try {
const data = await operation ();
return { data, error : null };
} catch (err) {
if (err instanceof MiroApiError ) {
console .error (`[Miro:${context} ] ${err.status} : ${err.message} ` );
return { data : null , error : err };
}
throw err;
}
}
Pattern 4: Multi-Tenant Client Factory
import { Miro , MiroApi } from '@mirohq/miro-api' ;
const clients = new Map <string , MiroApi >();
export async function getClientForUser (userId : string ): Promise <MiroApi > {
if (!clients.has (userId)) {
const miro = new Miro ({
clientId : process.env .MIRO_CLIENT_ID !,
clientSecret : process.env .MIRO_CLIENT_SECRET !,
redirectUrl : process.env .MIRO_REDIRECT_URI !,
});
if (!await miro.isAuthorized (userId)) {
throw new Error (`User ${userId} has not authorized Miro` );
}
const api = await miro.as (userId);
clients.set (userId, api);
}
return clients.get (userId)!;
}
Pattern 5: Response Validation with Zod import { z } from 'zod' ;
const MiroBoardSchema = z.object ({
id : z.string (),
type : z.literal ('board' ),
name : z.string (),
description : z.string ().optional (),
createdAt : z.string ().datetime (),
modifiedAt : z.string ().datetime (),
});
const MiroItemSchema = z.object ({
id : z.string (),
type : z.enum (['sticky_note' , 'shape' , 'card' , 'text' , 'frame' , 'image' , 'document' , 'embed' , 'app_card' ]),
data : z.record (z.unknown ()),
position : z.object ({ x : z.number (), y : z.number () }),
});
function validateBoardResponse (data : unknown ) {
return MiroBoardSchema .parse (data);
}
Error Handling Pattern Use Case Benefit Type-safe service Board/item CRUD Catches shape mismatches at compile time Item factory Bulk item creation Consistent defaults, validated params Error wrapper All API calls Classifies errors as retryable vs auth vs input Multi-tenant SaaS applications Isolates users, manages token lifecycle Zod validation Response parsing Runtime safety against API changes
Resources
Next Steps Apply these patterns in miro-core-workflow-a for board management operations.