Skip to content

GET /user

Get authenticated user information and accessible teams.

This endpoint returns the email address of the authenticated user and a list of teams they have access to. Use this endpoint to:

  • Verify authentication is working correctly
  • Discover which teams are available for scenario operations
  • Get team IDs to use in other API calls

Required: RSA signature-based authentication

X-Auth-Client-ID: {clientId}
X-Auth-Access-Token: {accessToken}
X-Auth-Timestamp: {timestamp}
X-Auth-Nonce: {nonce}
X-Auth-Signature: {signature}

Method: GET

URL: https://api.quickli.com/api/v1/user

Headers:

X-Auth-Client-ID: {clientId}
X-Auth-Access-Token: {accessToken}
X-Auth-Timestamp: {timestamp}
X-Auth-Nonce: {nonce}
X-Auth-Signature: {signature}
Content-Type: application/json

Body: None

{
"data": {
"email": "broker@example.com",
"teams": [
{
"id": "507f1f77bcf86cd799439011",
"name": "Team Alpha"
},
{
"id": "507f191e810c19729de860ea",
"name": "Team Beta"
}
]
},
"meta": {
"timestamp": "2025-11-03T10:30:00.000Z",
"version": "1.0.0"
}
}
FieldTypeDescription
emailstringUser’s email address
teamsarrayList of accessible teams
teams[].idstringTeam ObjectId (use this in API calls requiring teamId)
teams[].namestringTeam display name

Authentication failed - invalid signature or credentials.

{
"error": {
"code": "INVALID_SIGNATURE",
"message": "Request signature verification failed",
"timestamp": "2025-11-19T10:30:00.000Z"
}
}

Causes:

  • Invalid signature (signature verification failed)
  • Invalid client identifier
  • Invalid or expired access token
  • Missing required authentication headers
  • User not found

Solution: Verify your signature implementation and ensure all authentication headers are present and valid.

Terminal window
# Note: You need to generate the signature for each request
# See the Authentication Guide for signing implementation
curl -X GET https://api.quickli.com/api/v1/user \
-H "X-Auth-Client-ID: Loan Market Group" \
-H "X-Auth-Access-Token: abc123-uuid-token" \
-H "X-Auth-Timestamp: 2025-11-19T10:30:00.000Z" \
-H "X-Auth-Nonce: 550e8400-e29b-41d4-a716-446655440000" \
-H "X-Auth-Signature: {generated-signature}" \
-H "Content-Type: application/json"

Use this endpoint to verify your credentials and signing implementation:

Terminal window
curl -X GET https://api.quickli.com/api/v1/user \
-H "X-Auth-Client-ID: {clientId}" \
-H "X-Auth-Access-Token: {accessToken}" \
-H "X-Auth-Timestamp: {timestamp}" \
-H "X-Auth-Nonce: {nonce}" \
-H "X-Auth-Signature: {signature}"

If you get a 200 OK response, your authentication is configured correctly.

Before creating scenarios, get the list of teams you can use:

const user = await getUser();
if (user.teams.length === 0) {
console.error("No teams available. Contact your administrator.");
} else {
console.log("Available teams:");
user.teams.forEach((team) => {
console.log(`- ${team.name} (ID: ${team.id})`);
});
}

Let users choose which team to work with:

const user = await getUser();
// In a UI, present team options
const selectedTeamId = await promptUserToSelectTeam(user.teams);
// Use selected team in scenario creation
const scenario = await createScenario({
teamId: selectedTeamId,
scenario: {
/* ... */
},
});

Cache team data to avoid repeated calls:

class QuickliClient {
private teams: Team[] | null = null;
async getTeams(): Promise<Team[]> {
if (this.teams === null) {
const user = await this.getUser();
this.teams = user.teams;
}
return this.teams;
}
async getDefaultTeamId(): Promise<string> {
const teams = await this.getTeams();
if (teams.length === 0) {
throw new Error("No teams available");
}
return teams[0].id;
}
}

Your API access grant is scoped to one organization. All teams returned belong to that organization.

The teams returned are those you have explicit permission to access via your ApiAccessGrant. You can:

  • Create scenarios in any of these teams
  • Read scenarios belonging to these teams
  • Update scenarios in these teams

You cannot access:

  • Teams from other organizations
  • Teams not included in your access grant

When creating scenarios, if you don’t specify a teamId, the API uses the first team in your list:

// These are equivalent:
await createScenario({
scenario: {
/* ... */
},
});
await createScenario({
teamId: user.teams[0].id,
scenario: {
/* ... */
},
});

Wrap this endpoint in a client class:

class QuickliClient {
constructor(
private clientId: string,
private accessToken: string,
private privateKey: string,
) {}
private generateHeaders(method: string, path: string, body: unknown) {
const timestamp = new Date().toISOString();
const nonce = crypto.randomUUID();
let bodyString = "";
if (body && typeof body === "object" && Object.keys(body).length > 0) {
bodyString = JSON.stringify(body);
}
const bodyHash = crypto
.createHash("sha256")
.update(bodyString)
.digest("hex");
const canonicalRequest = `${method}\n${path}\n${timestamp}\n${nonce}\n${bodyHash}`;
const sign = crypto.createSign("RSA-SHA256");
sign.update(canonicalRequest);
const signature = sign.sign(this.privateKey, "base64");
return {
"X-Auth-Client-ID": this.clientId,
"X-Auth-Access-Token": this.accessToken,
"X-Auth-Timestamp": timestamp,
"X-Auth-Nonce": nonce,
"X-Auth-Signature": signature,
"Content-Type": "application/json",
};
}
private async request(path: string, method: string = "GET", body?: unknown) {
const headers = this.generateHeaders(method, path, body);
const response = await fetch(`https://api.quickli.com${path}`, {
method,
headers,
body: body ? JSON.stringify(body) : undefined,
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.message);
}
return response.json();
}
async getUser() {
const result = await this.request("/api/v1/user");
return result.data;
}
}
// Usage
const client = new QuickliClient(
process.env.QUICKLI_CLIENT_ID!,
process.env.QUICKLI_ACCESS_TOKEN!,
process.env.QUICKLI_PRIVATE_KEY!,
);
const user = await client.getUser();

Verify credentials during application startup:

async function initializeApp() {
try {
const user = await getUser();
console.log(`✓ Authenticated as ${user.email}`);
console.log(`${user.teams.length} team(s) available`);
return true;
} catch (error) {
console.error("✗ Authentication failed:", error.message);
return false;
}
}
// Only proceed if authentication works
if (!(await initializeApp())) {
process.exit(1);
}
interface User {
email: string;
teams: Team[];
}
interface Team {
id: string; // MongoDB ObjectId as string
name: string;
}
interface UserResponse {
data: User;
meta: {
timestamp: string;
version: string;
};
}
import { z } from "zod/v3";
const TeamSchema = z.object({
id: z.string().length(24), // MongoDB ObjectId
name: z.string(),
});
const UserSchema = z.object({
email: z.string().email(),
teams: z.array(TeamSchema),
});
const UserResponseSchema = z.object({
data: UserSchema,
meta: z.object({
timestamp: z.string(),
version: z.string(),
}),
});
// Validate response
const response = await fetch("...");
const json = await response.json();
const validated = UserResponseSchema.parse(json);

Last updated: 2025-11-19