Claude
Skills
Sign in
Back

clerk-backend-api

Included with Lifetime
$97 forever

Clerk Backend REST API explorer and executor. Browse tags, inspect endpoint schemas, and execute authenticated requests. Use when listing users, managing organizations, or calling any Clerk API endpoint.

Backend & APIsscripts

What this skill does


## Options context

User Prompt: $ARGUMENTS

## CRITICAL: Mandatory checks before EVERY write request

Before ANY POST / PATCH / PUT / DELETE, you MUST do ALL of the following in your response:

1. **Check CLERK_SECRET_KEY** — verify it is set:
   ```bash
   echo $CLERK_SECRET_KEY | head -c 10
   ```
   If empty, stop and ask the user. Do not proceed without a valid key.

2. **Check CLERK_BAPI_SCOPES** — run:
   ```bash
   echo $CLERK_BAPI_SCOPES
   ```
   Inspect the output. If scopes are missing or do not include the required write permission, tell the user: *"This is a write operation and your current scopes may not allow it. Rerun with --admin to bypass?"* Do NOT attempt the request and fail — ask first.

3. **For DELETE requests:** warn explicitly that the action is **IRREVERSIBLE** and list exactly what data will be permanently destroyed (user record, all sessions, all memberships, all associated data). Require explicit confirmation before proceeding. This warning is MANDATORY — never skip it.

4. **For metadata operations:** always explain which metadata type is being used and why (see Metadata types section below).

---

## FAST PATH: Common operations (use directly, no spec fetching needed)

For the operations below, skip spec fetching and execute immediately using these exact templates. Substitute `$CLERK_SECRET_KEY`, `$USER_ID`, `$ORG_ID`, `$EMAIL` as needed from the user's context.

### Create organization + invite member (two-step)

```bash
# Step 1 — Create organization
ORG=$(curl -s -X POST "https://api.clerk.com/v1/organizations" \
  -H "Authorization: Bearer $CLERK_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"name\": \"Acme Corp\", \"created_by\": \"$USER_ID\"}")
echo "$ORG" | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps(d, indent=2))"

# Step 2 — Extract org ID
ORG_ID=$(echo "$ORG" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")

# Step 3 — Invite member with role
curl -s -X POST "https://api.clerk.com/v1/organizations/${ORG_ID}/invitations" \
  -H "Authorization: Bearer $CLERK_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"email_address\": \"[email protected]\", \"role\": \"org:admin\"}" \
  | python3 -c "import sys,json; print(json.dumps(json.load(sys.stdin), indent=2))"
```

**Roles:** use `"org:admin"` or `"org:member"` (always prefix with `org:`).

### SDK equivalent (for Next.js / TypeScript projects with `@clerk/nextjs` or `@clerk/backend`)

```typescript
import { clerkClient } from '@clerk/nextjs/server'
// OR if using @clerk/backend directly:
// import { createClerkClient } from '@clerk/backend'
// const clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY })

// Step 1: Create organization
const org = await clerkClient.organizations.createOrganization({
  name: 'Acme Corp',
  createdBy: userId,  // required — the ID of the user creating the org
})

// Step 2: Invite member to the org
const invitation = await clerkClient.organizations.createOrganizationInvitation({
  organizationId: org.id,
  emailAddress: '[email protected]',
  role: 'org:admin',  // or 'org:member'
})
```

### Update user metadata

**Always explain the three metadata types before asking which to use:**

| Type | Field | Readable by | Writable by | Use for |
|------|-------|-------------|-------------|---------|
| Public | `public_metadata` | Client + Server | **Server only** | Plan tier, roles, feature flags the frontend reads |
| Private | `private_metadata` | **Server only** | **Server only** | Stripe IDs, compliance flags, internal identifiers |
| Unsafe | `unsafe_metadata` | Client + Server | Client + Server | Ephemeral UI state, onboarding steps (client-writable — avoid sensitive data) |

**For `plan: 'pro'` and `onboarded: true` — use `public_metadata`** (frontend-readable, server-writable):

```bash
curl -s -X PATCH "https://api.clerk.com/v1/users/${USER_ID}" \
  -H "Authorization: Bearer $CLERK_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"public_metadata": {"plan": "pro", "onboarded": true}}' \
  | python3 -c "import sys,json; d=json.load(sys.stdin); print(f'Updated user {d[\"id\"]}: public_metadata={d.get(\"public_metadata\")}')"
```

**SDK equivalent:**

```typescript
import { clerkClient } from '@clerk/nextjs/server'
// OR: import { createClerkClient } from '@clerk/backend'

await clerkClient.users.updateUser(userId, {
  publicMetadata: { plan: 'pro', onboarded: true },   // readable by client, writable server-only
  // privateMetadata: { stripeId: 'cus_xxx' },         // server-only read AND write
  // unsafeMetadata: { step: 'welcome' },              // client-writable, avoid sensitive data
})
```

**Note:** REST API uses `snake_case` (`public_metadata`). SDK uses `camelCase` (`publicMetadata`).

### List users (last 7 days)

```bash
curl -s "https://api.clerk.com/v1/users?limit=100&offset=0&order_by=-created_at&created_at=gt:$(date -d '7 days ago' +%s 2>/dev/null || date -v-7d +%s)000" \
  -H "Authorization: Bearer $CLERK_SECRET_KEY" \
  | python3 -c "
import sys, json
data = json.load(sys.stdin)
if isinstance(data, list):
    print(f'Found {len(data)} users:')
    for u in data:
        print(f'  {u[\"id\"]}: {u.get(\"email_addresses\", [{}])[0].get(\"email_address\", \"no email\")}')
else:
    print(json.dumps(data, indent=2))
"
```

### Delete user (confirm required)

```bash
# ONLY run after explicit user confirmation
curl -s -X DELETE "https://api.clerk.com/v1/users/${USER_ID}" \
  -H "Authorization: Bearer $CLERK_SECRET_KEY" \
  | python3 -c "import sys,json; d=json.load(sys.stdin); print(f'Deleted: {d}')"
```

---

## Clerk Backend API — Full Endpoint Reference

Base URL: `https://api.clerk.com/v1`
Auth: `Authorization: Bearer $CLERK_SECRET_KEY` on every request.

### Users

**List users**
```
GET /v1/users
Query params: limit (max 500, default 10), offset, order_by (+/-created_at, +/-updated_at, +/-email_address, +/-web3wallet, +/-first_name, +/-last_name, +/-phone_number, +/-username, +/-last_active_at, +/-last_sign_in_at), email_address[], phone_number[], username[], web3wallet[], user_id[], query, created_at (ISO 8601 range: gt:TIMESTAMP or lt:TIMESTAMP in Unix ms)
Returns: array of User objects
```

**Get user**
```
GET /v1/users/{user_id}
Returns: User object
```

**Update user**
```
PATCH /v1/users/{user_id}
Body (JSON, snake_case): { public_metadata, private_metadata, unsafe_metadata, first_name, last_name, username, ... }
```

**Delete user — IRREVERSIBLE**
```
DELETE /v1/users/{user_id}
Destroys: user record, all sessions, all memberships, all associated data
Returns: { id, object, deleted: true }
```
Always warn the user this is permanent and confirm before proceeding.

### Organizations

**Create organization**
```
POST /v1/organizations
Body: { name: string, created_by: string (user_id), public_metadata?, private_metadata?, max_allowed_memberships? }
Returns: Organization object with { id, name, slug, ... }
```

**List organizations**
```
GET /v1/organizations
Query params: limit, offset, query, order_by
```

**Invite member**
```
POST /v1/organizations/{organization_id}/invitations
Body: { email_address: string, role: string ("org:admin" or "org:member"), public_metadata?, private_metadata? }
Returns: OrganizationInvitation object
```

---

## How to execute requests

**ALWAYS execute requests with direct `curl` commands.** Use the spec-extraction scripts (`api-specs-context.sh`, `extract-tags.js`, `extract-endpoint-detail.sh`) to discover endpoints, but make actual API calls with `curl`. Do NOT use `scripts/execute-request.sh` — it's a local dev helper, not for agent use.

Template for GET requests:
```bash
curl -s "https://api.clerk.com/v1${PATH}${QUERY_STRING}" \
  -H "Authorization: Bearer $CLERK_SECRET_KEY"
```

Template for POST/PATCH requests:
```bash
curl -s -X ${METHOD} "https://api.clerk.com/v1${PATH}" \
  -H "Authorization: Bearer $CLERK_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d
Files: 7
Size: 35.0 KB
Complexity: 61/100
Category: Backend & APIs

Related in Backend & APIs