API / Getting started
Authentication
Personal tokens and the OAuth flow.
Authentication
What a token is
A token is a long random string that stands in for a designer's login. Your tool sends it with every request, and we use it to work out whose data you are touching and what you are allowed to do with it. Treat it like a password: keep it on your server, never in front-end code or a public repository.
You send it in a header on every call. "Bearer" just means whoever holds the token gets the access, which is exactly why it must not leak.
Authorization: Bearer YOUR_TOKEN
What a scope is
A scope is a single permission attached to a token, such as "read components" or "write components". A token only carries the scopes it was given, and an endpoint refuses any token missing the one it needs.
This exists so a designer can let your tool do its job without handing over their whole account. Ask for the fewest scopes you need: they see the list before approving, and a long one is a reason to say no. The full table is further down this page.
Which of the two do you need?
There are two ways to get a token, and the right one depends on who runs your software.
| If your tool is… | Use |
|---|---|
| A script, a CLI, or something the designer installs and runs themselves. Also: you, building for your own account. | A personal access token. They make one in their settings and paste it in. Nothing to build. |
| A website or hosted service that many designers sign in to. | OAuth. More work, but no designer ever pastes a credential into your app, and they can revoke you at any time. |
If you are not sure, start with a personal token. It takes a minute and proves your requests work. You can add OAuth later without changing a single API call, because both produce a token that the rest of the API treats identically.
Personal access tokens
A designer creates one in their own settings and pastes it into your tool. Right choice for a script, a CLI, or a self-hosted integration where the designer runs the software themselves. No consent screen involved.
OAuth2 authorization code with PKCE
The point of OAuth is that the designer types their password on our site, never in your app, and you receive a token instead. They see exactly what you are asking for, approve it, and can take it away later.
The flow below is the standard one. In outline: you send the designer here, they approve, we send them back to your app with a short-lived code, and your server swaps that code for a token. PKCE is the extra step that stops someone who intercepts the code from using it: you invent a random secret up front, send only a hash of it when you start, then prove you know the original when you redeem the code.
Register your app once in
API & Developer settings
to get a client_id (and a secret, if it is a server-side app).
You can start building immediately.
A newly registered app can authorize its own developer's account right away. Review is only needed before it can request access from other designers, so nothing blocks you while you build. Request it from the same settings page when you are ready to ship.
Step 1: send the designer to the consent screen
https://dustinsdesignerden.com/oauth/authorize
?client_id=YOUR_CLIENT_ID
&redirect_uri=https://yourtool.example.com/callback
&response_type=code
&scope=projects:read%20projects:write%20assets:read
&state=RANDOM_ANTI_CSRF_VALUE
&code_challenge=BASE64URL_SHA256_OF_VERIFIER
&code_challenge_method=S256
Generate a random code_verifier, derive the challenge as
base64url(sha256(verifier)), and keep both the verifier and the
state in the user's session.
Step 2: exchange the code, server to server
curl -X POST https://dustinsdesignerden.com/oauth/token \
-d grant_type=authorization_code \
-d client_id=YOUR_CLIENT_ID \
-d client_secret=YOUR_CLIENT_SECRET \
-d redirect_uri=https://yourtool.example.com/callback \
-d code_verifier=THE_VERIFIER_FROM_STEP_1 \
-d code=THE_CODE_FROM_THE_REDIRECT
Verify state matches before you do this. Public clients
(desktop, CLI, mobile) omit client_secret and rely on PKCE.
Step 3: refresh before it expires
curl -X POST https://dustinsdesignerden.com/oauth/token \
-d grant_type=refresh_token \
-d refresh_token=YOUR_REFRESH_TOKEN \
-d client_id=YOUR_CLIENT_ID \
-d client_secret=YOUR_CLIENT_SECRET
Access tokens last 1 hour, refresh tokens 30 days.
Scopes
Ask for the least you need. A token holding no scopes can reach nothing at all,
including /me, which any single scope unlocks.
The middle column is what the designer reads on the consent screen when deciding whether to trust you. The right column is what it actually unlocks, listed from the live route table, so it cannot drift from what the server enforces.
| Scope | What the designer is told it allows | Endpoints it unlocks |
|---|---|---|
projects:read |
See your projects and their details |
GET /projects
GET /projects/{project}
|
projects:write |
Create new projects, and edit the details of your existing ones, including the description shown publicly |
PATCH /projects/{project}
POST /projects
|
assets:read |
See the files stored in your projects |
GET /projects/{project}/assets
|
assets:write |
Upload and delete files in your storage |
DELETE /projects/{project}/assets
POST /projects/{project}/assets
POST /projects/{project}/assets/from-url
|
components:read |
See the components in your projects, how they are grouped into decks and stacks, and your custom mask shapes |
GET /masks
GET /projects/{project}/components
GET /projects/{project}/groups
|
components:write |
Create and update components, decks and stacks, and delete the ones it created |
DELETE /projects/{project}/components
DELETE /projects/{project}/components/{uniqueId}
DELETE /projects/{project}/groups/{group}
PATCH /projects/{project}/groups/{group}
POST /projects/{project}/components
POST /projects/{project}/components/batch
POST /projects/{project}/groups
PUT /projects/{project}/groups/{group}/members
|
webhooks:write |
Get notified when your projects or components change |
DELETE /webhooks/{webhook}
GET /webhooks
POST /webhooks
|
webhooks:write is the single scope covering every
webhook operation, listing included. An app only ever sees the webhooks it registered
itself, so being able to list them without being able to manage them would not be
useful, and a second consent checkbox for it would just be one more thing to explain
to the designer.