Skip to main content

TypeScript SDK

The official TypeScript client is generated from website/static/openapi.json into contrib/decidim-node-client and published as @octree/decidim-sdk.

Regenerate after API changes:

yarn gen:node-client

Install

yarn add @octree/decidim-sdk
# or link from the monorepo:
# yarn add file:./contrib/decidim-node-client

Bootstrap

import { Configuration, OAuthApi, SpacesApi } from "@octree/decidim-sdk";

const host = "https://your-org.example.org";
const apiBase = `${host}/api/rest_full/v0.3`;

const oauth = new OAuthApi(new Configuration({ basePath: apiBase }));

const { data: tokenPayload } = await oauth.createToken({
oauthGrantParam: {
grant_type: "client_credentials",
client_id: process.env.CLIENT_ID!,
client_secret: process.env.CLIENT_SECRET!,
scope: "public",
},
});

const accessToken = tokenPayload.access_token;
const spaces = new SpacesApi(new Configuration({ basePath: apiBase }));

const { data } = await spaces.listAssemblies({
authorization: `Bearer ${accessToken}`,
page: 1,
perPage: 10,
});

Protected routes use OpenAPI credentialFlowBearer / resourceOwnerFlowBearer security schemes. The generator still expects an authorization field on each request object (Bearer <token>) until a thin wrapper adds an Axios interceptor.

API classes (by tag)

ClassUse for
OAuthApicreateToken, introspectToken
SpacesApiParticipatory spaces (listAssemblies, showAssembly, searchSpaces, …)
ComponentsApisearchComponents, showProposalComponent, …
ProposalsApiPublished proposals, votes (castProposalVote, listProposalVotes)
DraftProposalsApiDraft lifecycle (getDraftProposal, publishDraftProposalAsync, …)
JobsApiPoll async work (getJob, listJobs)
AttachmentsApiList, show, attachmentsDirectUpload
FormsApiQuestionnaires, answers, questions
BlogsApiBlog posts (listBlogPosts, createBlogPostAsync, …)
UsersApilistUsers, magic links, extended data
OrganizationsApilistOrganizations, getOrganization, updateOrganization
OrganizationsExtendedDataApiOrg extended data hash
RolesApiAPI client roles

Naming cheat sheet

MethodMeaning
showAssembly({ id })GET one assembly (not a list)
listAssemblies()List assemblies
castProposalVote()Cast a vote on a published proposal
listProposalVotes()List vote records
publishDraftProposalAsync()Async publish → poll jobs.getJob
publishDraftProposal()Sync publish
createBlogPostAsync()Returns rest_full_api_job_accepted (202)
createAnswersAsync()Forms async submit (submission request envelope)

Async jobs

import { BlogsApi, JobsApi, Configuration } from "@octree/decidim-sdk";

const blogs = new BlogsApi(config);
const jobs = new JobsApi(config);

const { data: accepted } = await blogs.createBlogPostAsync({
authorization: `Bearer ${token}`,
body: { data: { component_id: 1, attributes: { title: { en: "Hi" }, body: { en: "…" } } } },
});

const jobId = accepted.job_id;
const { data: job } = await jobs.getJob({ uuid: jobId });

Browser-only endpoints

Do not call UsersApi.signInWithMagicLink from server code — it performs an HTTP redirect for end-user browsers. Use generateMagicLink and send users the URL instead.

Filters

Query parameters are camelCase in the SDK (e.g. filterManifestNameEq) and map to filter[manifest_name_eq] in HTTP.

See also: Integrator quickstart, Async and jobs, Dev: generate clients.