openapi: 3.0.3 info: title: esc Profile API description: | REST API for HR profile assessments - Assessment tests for recruiting and talent development. ## Authentication All authenticated endpoints require a Bearer Token in the Authorization header: ``` Authorization: Bearer pk_live_xxx ``` ## Rate Limiting - 100 requests per minute per API key - On exceeding: HTTP 429 ## Workflow 1. **View products** - `GET /products` (public) 2. **Purchase package** - `POST /orders` (creates Stripe Checkout) 3. **Check balance** - `GET /balance` 4. **Invite candidate** - `POST /invites` 5. **Get results** - `GET /invites/{id}/results` (JSON) or `GET /invites/{id}/report` (PDF) 6. **Match with profile** - `GET /invites/{id}/match?profile_id=jp_xxx` ## New in v1.4 - **Profiles**: List ALL completed assessments (API + Admin Tool) - **Profile Details**: Get full results by session ID ## New in v1.3 - **Teams**: Group candidates for team analysis and reports - **Team Reports**: Generate team-wide analysis reports - **Team Export**: Export team data as CSV/JSON ## New in v1.2 - **Search**: Find candidates across all completed assessments - **Job Profiles**: Create and manage ideal candidate profiles - **Matching**: Compare candidates against job profiles - **Full Results**: Complete JSON export of all dimensions - **Reminders**: Send up to 3 reminder emails per invite - **Cancel Invites**: Delete pending invites version: 1.4.0 contact: email: ralph.koebler@escprofile.com url: https://www.escprofile.com license: name: Proprietary url: https://www.escprofile.com/terms/ servers: - url: https://www.escprofile.com/api/v1 description: Production server tags: - name: Discovery description: API overview and product catalog (public) - name: Registration description: Self-service API key registration (public) - name: Account description: Account information and settings - name: Orders description: Orders and payments - name: Execution description: Invite candidates and retrieve results - name: Results description: Assessment results and reports - name: Search description: Search across completed assessments - name: Invoices description: View and download invoices - name: GDPR description: GDPR/DSGVO compliant data deletion - name: Job Profiles description: Manage job profiles for candidate matching - name: Matching description: Compare candidates with job profiles - name: Webhooks description: Event notifications - name: Teams description: Manage candidate teams for group analysis and reports - name: Profiles description: View all completed assessments (profiles) paths: /: get: tags: [Discovery] summary: API Information description: Returns API metadata and available endpoints operationId: getApiInfo responses: '200': description: API information content: application/json: schema: $ref: '#/components/schemas/ApiInfo' /request-trial: post: tags: [Registration] summary: Request trial access description: | Request a free trial access with 3 credits. The request is manually reviewed - you will receive an email with your credentials within 24 hours. Note: Consumer email addresses (Gmail, GMX, etc.) are not accepted. operationId: requestTrial requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RequestTrialRequest' example: company: "AI Startup Ltd" email: "dev@ai-startup.com" contact_name: "John Smith" use_case: "Integration into our ATS for automated candidate assessments" website: "https://ai-startup.com" responses: '200': description: Request received content: application/json: schema: $ref: '#/components/schemas/RequestTrialResponse' '400': description: Invalid input or consumer email content: application/json: schema: $ref: '#/components/schemas/Error' /register: post: tags: [Registration] summary: Register API access description: | Self-service registration for new API customers. Creates a new customer account and generates an API key. The key is only shown once in the response - save it immediately! Optionally specify a product_id to directly create a Stripe Checkout session for purchasing credits. operationId: registerApiAccess requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RegisterRequest' example: email: "developer@example.com" company: "Example Ltd" name: "John Smith" address: "123 Main Street" zip: "10001" city: "New York" country: "US" vat_id: "US12345678" billing_contact: "Accounting" phone: "+1 212 555 1234" website: "https://www.example.com" product_id: "pa-pack-10" mode: "live" responses: '201': description: Registration successful content: application/json: schema: $ref: '#/components/schemas/RegisterResponse' '400': description: Invalid input (email or company missing) content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: Email already registered content: application/json: schema: $ref: '#/components/schemas/Error' /products: get: tags: [Discovery] summary: List products description: Returns available assessment products with prices (public, no authentication required) operationId: listProducts parameters: - name: category in: query schema: type: string description: Filter by category - name: max_price in: query schema: type: number description: Maximum price - name: min_credits in: query schema: type: integer description: Minimum credits responses: '200': description: Product list content: application/json: schema: $ref: '#/components/schemas/ProductList' /orders: post: tags: [Orders] summary: Create order description: Creates a new order and returns the Stripe Checkout URL operationId: createOrder security: - bearerAuth: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateOrderRequest' responses: '201': description: Order created content: application/json: schema: $ref: '#/components/schemas/OrderResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' /orders/{orderId}: get: tags: [Orders] summary: Get order status description: Check the status of an order operationId: getOrder security: - bearerAuth: [] parameters: - name: orderId in: path required: true schema: type: string example: ord_abc123xyz responses: '200': description: Order details content: application/json: schema: $ref: '#/components/schemas/OrderStatus' '404': $ref: '#/components/responses/NotFound' /balance: get: tags: [Execution] summary: Check balance description: Get current credit balance and package details operationId: getBalance security: - bearerAuth: [] responses: '200': description: Balance information content: application/json: schema: $ref: '#/components/schemas/BalanceResponse' '401': $ref: '#/components/responses/Unauthorized' /account: get: tags: [Account] summary: Get account information description: | Retrieve account details for the authenticated API customer. **Returns:** - Company and contact information - Billing address - Active API keys (prefix only, not full key) - Account status and type - Personal assessment link operationId: getAccount security: - bearerAuth: [] responses: '200': description: Account information content: application/json: schema: $ref: '#/components/schemas/AccountResponse' '401': $ref: '#/components/responses/Unauthorized' '404': description: Account not found content: application/json: schema: $ref: '#/components/schemas/Error' /invoices: get: tags: [Invoices] summary: List invoices description: | List all invoices for your account. **Filtering:** - `status`: Filter by payment status (paid, unpaid, all) **Returns:** - List of invoices with amounts and payment status - Summary with total amounts operationId: listInvoices security: - bearerAuth: [] parameters: - name: status in: query schema: type: string enum: [paid, unpaid, all] default: all description: Filter by payment status - name: limit in: query schema: type: integer default: 50 maximum: 100 description: Maximum invoices to return - name: offset in: query schema: type: integer default: 0 description: Pagination offset responses: '200': description: Invoice list content: application/json: schema: $ref: '#/components/schemas/InvoiceListResponse' '401': $ref: '#/components/responses/Unauthorized' /invoices/{invoiceId}: get: tags: [Invoices] summary: Get invoice details description: | Get detailed information about a specific invoice including line items. operationId: getInvoice security: - bearerAuth: [] parameters: - name: invoiceId in: path required: true schema: type: string example: inv_12345 responses: '200': description: Invoice details content: application/json: schema: $ref: '#/components/schemas/InvoiceDetailResponse' '404': $ref: '#/components/responses/NotFound' /invoices/{invoiceId}/pdf: get: tags: [Invoices] summary: Download invoice PDF description: | Download the invoice as a PDF file. The PDF includes: - Company header and billing address - Invoice number and date - Line items with amounts - VAT calculation (if applicable) - Payment details operationId: downloadInvoicePdf security: - bearerAuth: [] parameters: - name: invoiceId in: path required: true schema: type: string example: inv_12345 responses: '200': description: PDF file content: application/pdf: schema: type: string format: binary '404': $ref: '#/components/responses/NotFound' /invites: post: tags: [Execution] summary: Create invite description: | Invite a candidate to a profile assessment. **Requirements:** - At least 1 available credit - Maximum 10 pending invites at a time Credits are only deducted when the candidate completes the assessment. operationId: createInvite security: - bearerAuth: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateInviteRequest' responses: '201': description: Invite created content: application/json: schema: $ref: '#/components/schemas/InviteResponse' '402': description: Insufficient credits content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: Too many pending invites (max. 10) content: application/json: schema: $ref: '#/components/schemas/Error' get: tags: [Execution] summary: List invites description: List all invites with optional filtering operationId: listInvites security: - bearerAuth: [] parameters: - name: status in: query schema: type: string enum: [pending, started, completed, expired] - name: limit in: query schema: type: integer default: 20 maximum: 100 - name: offset in: query schema: type: integer default: 0 responses: '200': description: Invite list content: application/json: schema: $ref: '#/components/schemas/InviteList' /invites/{inviteId}: get: tags: [Execution] summary: Get invite status description: Check the status of a specific invite operationId: getInvite security: - bearerAuth: [] parameters: - name: inviteId in: path required: true schema: type: string example: inv_abc123xyz responses: '200': description: Invite details content: application/json: schema: $ref: '#/components/schemas/InviteResponse' '404': $ref: '#/components/responses/NotFound' delete: tags: [Execution] summary: Cancel invite description: | Cancel a pending invite. Only invites with status "pending" can be cancelled. Started or completed invites cannot be cancelled. operationId: deleteInvite security: - bearerAuth: [] parameters: - name: inviteId in: path required: true schema: type: string example: inv_abc123xyz responses: '200': description: Invite cancelled content: application/json: schema: $ref: '#/components/schemas/DeleteInviteResponse' '400': description: Cannot cancel (not pending) content: application/json: schema: $ref: '#/components/schemas/Error' '404': $ref: '#/components/responses/NotFound' /invites/{inviteId}/remind: post: tags: [Execution] summary: Send reminder description: | Send a reminder email to the candidate. **Limits:** - Maximum 3 reminders per invite - Minimum 24 hours between reminders - Only for pending or started invites operationId: sendReminder security: - bearerAuth: [] parameters: - name: inviteId in: path required: true schema: type: string example: inv_abc123xyz responses: '200': description: Reminder sent content: application/json: schema: $ref: '#/components/schemas/ReminderResponse' '400': description: Invalid status or expired content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: Too many reminders or too soon content: application/json: schema: $ref: '#/components/schemas/Error' /invites/{inviteId}/report: get: tags: [Execution] summary: Download PDF report description: | Download the assessment PDF report for a completed invite. Available report types: - **standard**: General profile analysis (default) - **leadership**: Leadership-focused analysis - **sales**: Sales-focused analysis operationId: getReport security: - bearerAuth: [] parameters: - name: inviteId in: path required: true schema: type: string example: inv_abc123xyz - name: type in: query schema: type: string enum: [standard, leadership, sales] default: standard description: Report type/focus - name: lang in: query schema: type: string enum: [en, de] default: en description: Report language responses: '200': description: PDF report file content: application/pdf: schema: type: string format: binary '400': description: Assessment not completed or invalid parameters content: application/json: schema: $ref: '#/components/schemas/Error' '404': $ref: '#/components/responses/NotFound' /invites/{inviteId}/results: get: tags: [Results] summary: Get full results (JSON) description: | Retrieve complete assessment results as structured JSON. Contains all dimension scores, Graves values, and candidate info. **Includes:** - 16 operative dimensions with raw %, c-value (0-10), and labels - 6 Graves values (G2-G7) - Wir-Ich ratio - Norm group information - Optional descriptions for each dimension operationId: getResultsJson security: - bearerAuth: [] parameters: - name: inviteId in: path required: true schema: type: string example: inv_abc123xyz - name: include_descriptions in: query schema: type: boolean default: false description: Include dimension descriptions responses: '200': description: Full assessment results content: application/json: schema: $ref: '#/components/schemas/FullResultsResponse' '400': description: Assessment not completed content: application/json: schema: $ref: '#/components/schemas/Error' '404': $ref: '#/components/responses/NotFound' /invites/{inviteId}/match: get: tags: [Matching] summary: Match with job profile description: | Compare a candidate's assessment results with a job profile. Returns overall match score and per-dimension breakdown. **Match scores:** - 90-100: Excellent (green) - 70-89: Good (lightgreen) - 50-69: Acceptable/Marginal (yellow/orange) - 0-49: Critical (red) operationId: matchWithProfile security: - bearerAuth: [] parameters: - name: inviteId in: path required: true schema: type: string example: inv_abc123xyz - name: profile_id in: query required: true schema: type: string description: Job profile ID (jp_xxx format) example: jp_634 - name: include_details in: query schema: type: boolean default: false description: Include profile tolerance ranges responses: '200': description: Match results content: application/json: schema: $ref: '#/components/schemas/MatchResponse' '400': description: Assessment not completed or profile has no dimensions content: application/json: schema: $ref: '#/components/schemas/Error' '404': $ref: '#/components/responses/NotFound' /results/{inviteId}: get: tags: [Results] summary: Get results (legacy) description: Retrieve assessment results for a completed invite operationId: getResults security: - bearerAuth: [] parameters: - name: inviteId in: path required: true schema: type: string example: inv_abc123xyz - name: include_raw in: query schema: type: boolean default: false description: Include raw session data responses: '200': description: Assessment results content: application/json: schema: $ref: '#/components/schemas/FullResultsResponse' '202': description: Assessment not yet completed '404': $ref: '#/components/responses/NotFound' /search: get: tags: [Search] summary: Search assessments description: | Search across all completed assessments for your account. **Search options:** - `q`: General search across name and email - `name`: Search by name only - `email`: Search by email only - `date_from`/`date_to`: Filter by completion date At least one search parameter is required. operationId: searchAssessments security: - bearerAuth: [] parameters: - name: q in: query schema: type: string description: General search query (searches name and email) example: "john" - name: name in: query schema: type: string description: Search by name only - name: email in: query schema: type: string description: Search by email only - name: date_from in: query schema: type: string format: date description: Filter by completion date (from) example: "2026-01-01" - name: date_to in: query schema: type: string format: date description: Filter by completion date (to) example: "2026-12-31" - name: limit in: query schema: type: integer default: 20 maximum: 100 description: Maximum results to return - name: offset in: query schema: type: integer default: 0 description: Pagination offset - name: include_results in: query schema: type: boolean default: false description: Include basic dimension scores in results responses: '200': description: Search results content: application/json: schema: $ref: '#/components/schemas/SearchResponse' '400': description: Missing search query content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' /job-profiles: get: tags: [Job Profiles] summary: List job profiles description: Get all job profiles for your account operationId: listJobProfiles security: - bearerAuth: [] responses: '200': description: Profile list content: application/json: schema: $ref: '#/components/schemas/JobProfileList' post: tags: [Job Profiles] summary: Create job profile description: | Create a new job profile with ideal dimension values. **Dimensions available:** - Motivation: goal_orientation, problem_solving - Work Style: proactive, reflective - Decision Making: internal, external - Perception: sameness, difference - Information: global, detail - Resilience: failure_tolerance, stability - Approach: procedural, options - Orientation: practical, people, process - Values: graves2_security through graves7_growth operationId: createJobProfile security: - bearerAuth: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateJobProfileRequest' responses: '201': description: Profile created content: application/json: schema: $ref: '#/components/schemas/JobProfileResponse' '400': $ref: '#/components/responses/BadRequest' /job-profiles/{profileId}: get: tags: [Job Profiles] summary: Get job profile description: Get details of a specific job profile including all dimensions operationId: getJobProfile security: - bearerAuth: [] parameters: - name: profileId in: path required: true schema: type: string example: jp_634 responses: '200': description: Profile details content: application/json: schema: $ref: '#/components/schemas/JobProfileResponse' '404': $ref: '#/components/responses/NotFound' put: tags: [Job Profiles] summary: Update job profile description: Update an existing job profile operationId: updateJobProfile security: - bearerAuth: [] parameters: - name: profileId in: path required: true schema: type: string example: jp_634 requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateJobProfileRequest' responses: '200': description: Profile updated content: application/json: schema: $ref: '#/components/schemas/JobProfileResponse' '404': $ref: '#/components/responses/NotFound' delete: tags: [Job Profiles] summary: Delete job profile description: Delete a job profile (soft delete) operationId: deleteJobProfile security: - bearerAuth: [] parameters: - name: profileId in: path required: true schema: type: string example: jp_634 responses: '200': description: Profile deleted content: application/json: schema: $ref: '#/components/schemas/DeleteJobProfileResponse' '404': $ref: '#/components/responses/NotFound' /gdpr/candidates: get: tags: [GDPR] summary: List candidates for deletion description: | List all candidates eligible for GDPR-compliant data deletion. **Filter options:** - `status=active`: Candidates with personal data (default) - `status=deleted`: Already anonymized candidates - `status=all`: All candidates Candidates marked as "protected" cannot be deleted. operationId: listGdprCandidates security: - bearerAuth: [] parameters: - name: status in: query schema: type: string enum: [active, deleted, all] default: active description: Filter by deletion status - name: limit in: query schema: type: integer default: 50 maximum: 100 - name: offset in: query schema: type: integer default: 0 responses: '200': description: Candidate list content: application/json: schema: $ref: '#/components/schemas/GdprCandidateListResponse' '401': $ref: '#/components/responses/Unauthorized' /gdpr/candidates/{sessionId}: get: tags: [GDPR] summary: Get candidate deletion status description: Check if a candidate can be deleted and their current status operationId: getGdprCandidateStatus security: - bearerAuth: [] parameters: - name: sessionId in: path required: true schema: type: integer description: Session ID of the candidate responses: '200': description: Candidate status content: application/json: schema: $ref: '#/components/schemas/GdprCandidateStatusResponse' '404': $ref: '#/components/responses/NotFound' delete: tags: [GDPR] summary: Delete candidate data (GDPR) description: | Anonymize all personal data for a candidate according to GDPR requirements. **This action:** - Replaces personal data (name, email, IP) with "dsgvo" / "Anonym" - Removes team and job profile assignments - Deletes activity logs - Is **irreversible** **Prerequisites:** - Candidate must not be protected (`protected: false`) - Candidate must not already be anonymized Assessment results (scores, dimensions) are preserved for statistical purposes. operationId: deleteGdprCandidate security: - bearerAuth: [] parameters: - name: sessionId in: path required: true schema: type: integer description: Session ID of the candidate responses: '200': description: Data anonymized successfully content: application/json: schema: $ref: '#/components/schemas/GdprDeleteResponse' '400': description: Already anonymized content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Candidate is protected from deletion content: application/json: schema: $ref: '#/components/schemas/Error' '404': $ref: '#/components/responses/NotFound' /gdpr/deletions: get: tags: [GDPR] summary: List completed deletions description: | Audit log of all GDPR deletions performed for your account. Useful for compliance documentation. operationId: listGdprDeletions security: - bearerAuth: [] parameters: - name: limit in: query schema: type: integer default: 50 maximum: 100 - name: offset in: query schema: type: integer default: 0 responses: '200': description: Deletion history content: application/json: schema: $ref: '#/components/schemas/GdprDeletionListResponse' '401': $ref: '#/components/responses/Unauthorized' /webhooks: post: tags: [Webhooks] summary: Register webhook description: Register a URL to receive event notifications operationId: createWebhook security: - bearerAuth: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateWebhookRequest' responses: '201': description: Webhook created content: application/json: schema: $ref: '#/components/schemas/WebhookResponse' get: tags: [Webhooks] summary: List webhooks description: List all registered webhooks operationId: listWebhooks security: - bearerAuth: [] responses: '200': description: Webhook list content: application/json: schema: $ref: '#/components/schemas/WebhookList' /teams: get: tags: [Teams] summary: List teams description: | Get all teams for your account. **Filter options:** - `status=active`: Active teams (default) - `status=inactive`: Inactive/archived teams - `status=all`: All teams operationId: listTeams security: - bearerAuth: [] parameters: - name: status in: query schema: type: string enum: [active, inactive, all] default: active description: Filter by team status - name: limit in: query schema: type: integer default: 50 maximum: 100 - name: offset in: query schema: type: integer default: 0 responses: '200': description: Team list content: application/json: schema: $ref: '#/components/schemas/TeamListResponse' '401': $ref: '#/components/responses/Unauthorized' post: tags: [Teams] summary: Create team description: | Create a new team for grouping candidates. Teams can be used to: - Group candidates for team analysis - Generate team reports (leadership, sales, employee) - Export team data as CSV operationId: createTeam security: - bearerAuth: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateTeamRequest' responses: '201': description: Team created content: application/json: schema: $ref: '#/components/schemas/TeamResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' /teams/{teamId}: get: tags: [Teams] summary: Get team details description: | Get team details including member list. Returns all team members with their session info and assessment completion status. Anonymized candidates (GDPR deleted) are excluded from the member list. operationId: getTeam security: - bearerAuth: [] parameters: - name: teamId in: path required: true schema: type: integer description: Team ID responses: '200': description: Team details with members content: application/json: schema: $ref: '#/components/schemas/TeamDetailResponse' '404': $ref: '#/components/responses/NotFound' put: tags: [Teams] summary: Update team description: Update team name, subtitle, or description operationId: updateTeam security: - bearerAuth: [] parameters: - name: teamId in: path required: true schema: type: integer requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateTeamRequest' responses: '200': description: Team updated content: application/json: schema: $ref: '#/components/schemas/TeamResponse' '404': $ref: '#/components/responses/NotFound' delete: tags: [Teams] summary: Delete team description: | Delete a team and all member assignments. **Warning:** This action cannot be undone. All member assignments will be removed. The candidates themselves are not affected - only the team grouping is removed. operationId: deleteTeam security: - bearerAuth: [] parameters: - name: teamId in: path required: true schema: type: integer responses: '200': description: Team deleted content: application/json: schema: $ref: '#/components/schemas/DeleteTeamResponse' '404': $ref: '#/components/responses/NotFound' /teams/{teamId}/members: post: tags: [Teams] summary: Add members to team description: | Add one or more candidates to the team. You can specify candidates by: - `session_ids`: Array of session IDs - `invite_ids`: Array of invite IDs (inv_xxx format) Candidates must belong to your account and have completed their assessment. Already existing members are skipped (not duplicated). operationId: addTeamMembers security: - bearerAuth: [] parameters: - name: teamId in: path required: true schema: type: integer requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AddTeamMembersRequest' responses: '200': description: Members added content: application/json: schema: $ref: '#/components/schemas/AddTeamMembersResponse' '400': description: No valid candidates provided content: application/json: schema: $ref: '#/components/schemas/Error' '404': $ref: '#/components/responses/NotFound' delete: tags: [Teams] summary: Remove all members description: | Remove all members from the team. The team itself remains - only the member assignments are deleted. Use DELETE /teams/{teamId} to delete the entire team. operationId: removeAllTeamMembers security: - bearerAuth: [] parameters: - name: teamId in: path required: true schema: type: integer responses: '200': description: All members removed content: application/json: schema: $ref: '#/components/schemas/RemoveAllMembersResponse' '404': $ref: '#/components/responses/NotFound' /teams/{teamId}/members/{sessionId}: delete: tags: [Teams] summary: Remove single member description: Remove a specific candidate from the team operationId: removeTeamMember security: - bearerAuth: [] parameters: - name: teamId in: path required: true schema: type: integer - name: sessionId in: path required: true schema: type: integer description: Session ID of the candidate to remove responses: '200': description: Member removed content: application/json: schema: $ref: '#/components/schemas/RemoveMemberResponse' '404': $ref: '#/components/responses/NotFound' /teams/{teamId}/export: get: tags: [Teams] summary: Export team data description: | Export team member data with all assessment dimensions. **Export includes:** - Candidate info (name, email, session ID) - All operative dimensions (normalized 0-100) - Graves values (G2-G7) - Assessment metadata **Formats:** - `csv`: Comma-separated values (default) - `json`: JSON array Anonymized candidates are excluded from export. operationId: exportTeam security: - bearerAuth: [] parameters: - name: teamId in: path required: true schema: type: integer - name: format in: query schema: type: string enum: [csv, json] default: csv description: Export format responses: '200': description: Export data content: text/csv: schema: type: string application/json: schema: $ref: '#/components/schemas/TeamExportResponse' '404': $ref: '#/components/responses/NotFound' /profiles: get: tags: [Profiles] summary: List all profiles description: | List all completed assessments (profiles) for your account. This endpoint returns ALL assessments, regardless of whether they were created via API or manually in the Admin Tool. **Parameters:** - `status`: Filter by completion status (completed, all) - `sort`: Sort order (newest, oldest, name) - `include_results`: Include basic dimension scores GDPR-anonymized candidates are automatically excluded. operationId: listProfiles security: - bearerAuth: [] parameters: - name: status in: query schema: type: string enum: [completed, all] default: completed description: Filter by status - name: sort in: query schema: type: string enum: [newest, oldest, name] default: newest description: Sort order - name: include_results in: query schema: type: boolean default: false description: Include basic dimension scores - name: limit in: query schema: type: integer default: 50 maximum: 100 - name: offset in: query schema: type: integer default: 0 responses: '200': description: Profile list content: application/json: schema: $ref: '#/components/schemas/ProfileListResponse' '401': $ref: '#/components/responses/Unauthorized' /profiles/{sessionId}: get: tags: [Profiles] summary: Get profile details description: | Get detailed information about a specific profile/assessment. Returns candidate info, assessment metadata, full dimension results, and team memberships. operationId: getProfile security: - bearerAuth: [] parameters: - name: sessionId in: path required: true schema: type: integer description: Session ID of the profile responses: '200': description: Profile details content: application/json: schema: $ref: '#/components/schemas/ProfileDetailResponse' '404': $ref: '#/components/responses/NotFound' components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: API Key description: 'Format: pk_live_[32-char-hex]' schemas: ApiInfo: type: object properties: success: type: boolean data: type: object properties: name: type: string version: type: string description: type: string ProductList: type: object properties: success: type: boolean data: type: object properties: products: type: array items: $ref: '#/components/schemas/Product' total: type: integer Product: type: object properties: productID: type: string name: type: string description: type: string offers: type: object properties: price: type: string priceCurrency: type: string credits: type: integer features: type: array items: type: string CreateOrderRequest: type: object required: - product_id properties: product_id: type: string example: pa-pack-10 email: type: string format: email OrderResponse: type: object properties: success: type: boolean data: type: object properties: order_id: type: string status: type: string product: type: object payment: type: object properties: amount: type: number currency: type: string checkout_url: type: string format: uri OrderStatus: type: object properties: success: type: boolean data: type: object properties: order_id: type: string status: type: string enum: [pending_payment, completed, cancelled] payment_status: type: string BalanceResponse: type: object properties: success: type: boolean data: type: object properties: customer: type: object balance: type: object properties: credits_available: type: integer credits_used: type: integer pending_invites: type: integer description: Number of pending invites (informational only, no reservation) packages: type: array items: type: object AccountResponse: type: object properties: success: type: boolean data: type: object properties: account: type: object properties: id: type: string example: cus_9000001 company: type: string slug: type: string description: URL slug for assessment link type: type: string enum: [standard, API, enterprise] status: type: string enum: [active, inactive, api_only] created_at: type: string format: date-time assessment_link: type: string format: uri description: Direct link for candidate assessments contact: type: object properties: email: type: string first_name: type: string last_name: type: string phone: type: string website: type: string address: type: string billing: type: object properties: email: type: string company: type: string street: type: string city: type: string vat_id: type: string attention: type: string description: Billing attention (z.Hd.) api_keys: type: array items: type: object properties: key_prefix: type: string example: pk_live_abc1 name: type: string mode: type: string enum: [live, test] created_at: type: string format: date-time last_used_at: type: string format: date-time rate_limit: type: integer permissions: type: array items: type: string links: type: object properties: balance: type: string invites: type: string job_profiles: type: string documentation: type: string InvoiceListResponse: type: object properties: success: type: boolean data: type: object properties: invoices: type: array items: $ref: '#/components/schemas/InvoiceSummary' summary: type: object properties: total_net: type: number total_gross: type: number currency: type: string pagination: type: object properties: total: type: integer limit: type: integer offset: type: integer has_more: type: boolean InvoiceSummary: type: object properties: id: type: string example: inv_12345 invoice_number: type: string example: "2026/1001/1" date: type: string format: date amount_net: type: number amount_gross: type: number currency: type: string status: type: string enum: [paid, unpaid] pdf_url: type: string InvoiceDetailResponse: type: object properties: success: type: boolean data: type: object properties: id: type: string invoice_number: type: string date: type: string format: date billing_address: type: object properties: company: type: string attention: type: string street: type: string city: type: string vat_id: type: string line_items: type: array items: $ref: '#/components/schemas/InvoiceLineItem' product: type: object nullable: true properties: id: type: integer name: type: string price_net: type: number amounts: type: object properties: net: type: number vat_rate: type: number vat_amount: type: number gross: type: number currency: type: string reverse_charge: type: boolean description: True if VAT reverse charge applies status: type: string enum: [paid, unpaid] notes: type: string nullable: true pdf_url: type: string InvoiceLineItem: type: object properties: description: type: string additional_text: type: string nullable: true amount_net: type: number nullable: true description: null for text-only lines CreateInviteRequest: type: object required: - email properties: email: type: string format: email description: Candidate email address name: type: string description: Candidate name (optional) product_type: type: string default: escprofile send_email: type: boolean default: true description: Send invitation email to candidate InviteResponse: type: object properties: success: type: boolean data: type: object properties: invite_id: type: string status: type: string enum: [pending, started, completed, expired] candidate: type: object properties: email: type: string name: type: string analysis_link: type: string format: uri created_at: type: string format: date-time InviteList: type: object properties: success: type: boolean data: type: object properties: invites: type: array items: $ref: '#/components/schemas/InviteResponse' total: type: integer ResultsResponse: type: object properties: success: type: boolean data: type: object properties: invite_id: type: string status: type: string candidate: type: object completed_at: type: string format: date-time scores: type: object additionalProperties: type: number overall_score: type: number report: type: object properties: pdf_url: type: string format: uri CreateWebhookRequest: type: object required: - url properties: url: type: string format: uri events: type: array items: type: string enum: [analysis.completed, analysis.started, order.completed] WebhookResponse: type: object properties: success: type: boolean data: type: object properties: webhook_id: type: string url: type: string secret: type: string description: HMAC signing key (shown only once) events: type: array items: type: string WebhookList: type: object properties: success: type: boolean data: type: object properties: webhooks: type: array items: type: object RequestTrialRequest: type: object required: - company - email - use_case properties: company: type: string description: Company name email: type: string format: email description: Company email (no consumer addresses like Gmail, GMX) contact_name: type: string description: Contact person name (optional) use_case: type: string description: Brief description of the intended use case website: type: string format: uri description: Company website (optional) RequestTrialResponse: type: object properties: success: type: boolean data: type: object properties: message: type: string example: "Trial request received. You will receive an email with your credentials within 24 hours." reference: type: string example: "trial_abc123" next_steps: type: array items: type: string RegisterRequest: type: object required: - email - company properties: email: type: string format: email description: Contact email for the API account company: type: string description: Company or organization name name: type: string description: Contact person (optional) address: type: string description: Street address (optional) example: "123 Main Street" zip: type: string description: Postal code (optional) example: "10001" city: type: string description: City (optional) example: "New York" country: type: string description: ISO country code (optional, default US) default: "US" example: "US" vat_id: type: string description: VAT ID for invoicing (optional) example: "US12345678" billing_contact: type: string description: Invoice recipient (attn.) example: "Accounting" phone: type: string description: Phone number (optional) example: "+1 212 555 1234" website: type: string format: uri description: Company website (optional) example: "https://www.example.com" product_id: type: string description: Product ID for immediate purchase (optional) enum: [pa-single, pa-pack-10, pa-pack-50] mode: type: string description: API key mode (optional, default live) enum: [live, test] default: "live" RegisterResponse: type: object properties: success: type: boolean data: type: object properties: message: type: string customer: type: object properties: id: type: string company: type: string email: type: string is_new: type: boolean api_key: type: object properties: key: type: string description: The full API key - SAVE IT! Shown only once. prefix: type: string mode: type: string permissions: type: array items: type: string rate_limit: type: integer order: type: object description: Only present if product_id was specified properties: order_id: type: string checkout_url: type: string format: uri next_steps: type: object additionalProperties: type: string Error: type: object properties: success: type: boolean example: false error: type: object properties: message: type: string code: type: string DeleteInviteResponse: type: object properties: success: type: boolean message: type: string data: type: object properties: invite_id: type: string candidate_email: type: string was_expired: type: boolean cancelled_at: type: string format: date-time ReminderResponse: type: object properties: success: type: boolean message: type: string data: type: object properties: invite_id: type: string candidate_email: type: string status: type: string reminder_number: type: integer reminders_remaining: type: integer sent_at: type: string format: date-time expires_at: type: string format: date-time days_until_expiry: type: integer FullResultsResponse: type: object properties: success: type: boolean data: type: object properties: invite_id: type: string candidate: type: object properties: name: type: string email: type: string gender: type: string assessment: type: object properties: completed_at: type: string format: date-time product_type: type: string dimensions: type: object description: All 16 operative dimensions additionalProperties: $ref: '#/components/schemas/DimensionScore' graves_values: type: object description: Graves spiral dynamics values (G2-G7) additionalProperties: $ref: '#/components/schemas/GravesScore' wir_ich_ratio: type: object properties: wir_percent: type: number ich_percent: type: number tendency: type: string norm_group: type: object properties: id: type: integer name: type: string reports: type: object properties: standard: type: string format: uri leadership: type: string format: uri sales: type: string format: uri SearchResponse: type: object properties: success: type: boolean data: type: object properties: query: type: object properties: q: type: string name: type: string email: type: string date_from: type: string date_to: type: string candidates: type: array items: $ref: '#/components/schemas/SearchCandidate' pagination: type: object properties: total: type: integer limit: type: integer offset: type: integer has_more: type: boolean SearchCandidate: type: object properties: session_id: type: integer invite_id: type: string nullable: true name: type: string first_name: type: string last_name: type: string email: type: string gender: type: string enum: [male, female, other] birth_date: type: string format: date started_at: type: string format: date-time completed_at: type: string format: date-time scores: type: object description: Only present when include_results=true properties: goal_orientation: type: number problem_solving: type: number proactive: type: number reflective: type: number internal: type: number external: type: number global: type: number detail: type: number links: type: object properties: results: type: string report: type: string DimensionScore: type: object properties: raw_percent: type: number description: Raw score as percentage (0-100) c_value: type: number description: Normalized C-value (0-10, mean=5) label: type: string enum: [Very Low, Low, Below Average, Average, Above Average, High, Very High] name: type: object properties: en: type: string de: type: string GravesScore: type: object properties: raw_percent: type: number c_value: type: number name: type: object properties: en: type: string de: type: string MatchResponse: type: object properties: success: type: boolean data: type: object properties: invite_id: type: string candidate: type: object properties: name: type: string email: type: string profile: type: object properties: id: type: string name: type: string type: type: string overall_match: type: number description: Overall match percentage (0-100) overall_rating: type: object properties: en: type: string de: type: string color: type: string enum: [green, lightgreen, yellow, orange, red] dimensions_matched: type: integer strengths: type: array items: type: string development_areas: type: array items: type: string recommendation: type: string match_details: type: object additionalProperties: $ref: '#/components/schemas/MatchDetail' MatchDetail: type: object properties: dimension: type: string label: type: object properties: en: type: string de: type: string candidate_value: type: number profile_ideal: type: number delta: type: number match_score: type: integer rating: type: object properties: en: type: string de: type: string color: type: string zone: type: string enum: [green, yellow, red] JobProfileList: type: object properties: success: type: boolean data: type: object properties: profiles: type: array items: $ref: '#/components/schemas/JobProfileSummary' total: type: integer JobProfileSummary: type: object properties: id: type: string example: jp_634 name: type: string name_en: type: string type: type: string dimensions_configured: type: integer active: type: boolean JobProfileResponse: type: object properties: success: type: boolean data: type: object properties: id: type: string name: type: string name_en: type: string type: type: string description: type: string active: type: boolean created_at: type: string format: date-time dimensions: type: object additionalProperties: $ref: '#/components/schemas/ProfileDimension' dimensions_count: type: integer ProfileDimension: type: object properties: db_name: type: string ideal: type: number description: Ideal C-value (0-10) ok_min: type: number description: Minimum acceptable value ok_max: type: number description: Maximum acceptable value critical_low: type: number description: Critical low threshold critical_high: type: number description: Critical high threshold CreateJobProfileRequest: type: object required: - name properties: name: type: string description: Profile name (German) name_en: type: string description: Profile name (English) type: type: string default: standard description: type: string dimensions: type: object description: Dimension configurations additionalProperties: type: object properties: ideal: type: number ok_min: type: number ok_max: type: number critical_low: type: number critical_high: type: number UpdateJobProfileRequest: type: object properties: name: type: string name_en: type: string type: type: string description: type: string active: type: boolean dimensions: type: object additionalProperties: type: object properties: ideal: type: number ok_min: type: number ok_max: type: number critical_low: type: number critical_high: type: number DeleteJobProfileResponse: type: object properties: success: type: boolean message: type: string data: type: object properties: id: type: string deleted: type: boolean GdprCandidateListResponse: type: object properties: success: type: boolean data: type: object properties: candidates: type: array items: $ref: '#/components/schemas/GdprCandidate' pagination: type: object properties: total: type: integer limit: type: integer offset: type: integer has_more: type: boolean GdprCandidate: type: object properties: session_id: type: integer invite_id: type: string nullable: true status: type: string enum: [active, anonymized] protected: type: boolean description: If true, candidate cannot be deleted personal_data: type: object nullable: true description: null if already anonymized properties: first_name: type: string last_name: type: string email: type: string birth_date: type: string gender: type: string assessment: type: object properties: type: type: string started_at: type: string completed_at: type: string GdprCandidateStatusResponse: type: object properties: success: type: boolean data: type: object properties: session_id: type: integer invite_id: type: string nullable: true status: type: string enum: [active, anonymized] protected: type: boolean can_delete: type: boolean description: True if candidate can be deleted (not protected, not already anonymized) personal_data: type: object nullable: true assessment: type: object GdprDeleteResponse: type: object properties: success: type: boolean data: type: object properties: status: type: string enum: [success, partial] message: type: string session_id: type: integer anonymized: type: object properties: original_name: type: string original_email: type: string deleted_at: type: string format: date-time affected_tables: type: array items: type: string GdprDeletionListResponse: type: object properties: success: type: boolean data: type: object properties: deletions: type: array items: type: object properties: session_id: type: integer invite_id: type: string nullable: true assessment_type: type: string original_date: type: string status: type: string pagination: type: object properties: total: type: integer limit: type: integer offset: type: integer has_more: type: boolean TeamListResponse: type: object properties: success: type: boolean data: type: object properties: teams: type: array items: $ref: '#/components/schemas/TeamSummary' pagination: type: object properties: total: type: integer limit: type: integer offset: type: integer has_more: type: boolean TeamSummary: type: object properties: id: type: integer example: 634 title: type: string example: "Sales Team Q1 2026" subtitle: type: string example: "Regional Sales" description: type: string status: type: string enum: [active, inactive] member_count: type: integer created_at: type: string format: date-time created_by: type: string TeamResponse: type: object properties: success: type: boolean data: $ref: '#/components/schemas/TeamSummary' TeamDetailResponse: type: object properties: success: type: boolean data: type: object properties: id: type: integer title: type: string subtitle: type: string description: type: string status: type: string enum: [active, inactive] created_at: type: string format: date-time created_by: type: string members: type: array items: $ref: '#/components/schemas/TeamMember' member_count: type: integer TeamMember: type: object properties: session_id: type: integer invite_id: type: string nullable: true first_name: type: string last_name: type: string email: type: string assessment_type: type: string completed_at: type: string format: date-time CreateTeamRequest: type: object required: - title properties: title: type: string description: Team name/title example: "Sales Team Q1 2026" subtitle: type: string description: Additional subtitle (optional) example: "Regional Sales" description: type: string description: Team description (optional) UpdateTeamRequest: type: object properties: title: type: string subtitle: type: string description: type: string DeleteTeamResponse: type: object properties: success: type: boolean data: type: object properties: id: type: integer deleted: type: boolean members_removed: type: integer message: type: string AddTeamMembersRequest: type: object properties: session_ids: type: array items: type: integer description: Array of session IDs to add invite_ids: type: array items: type: string description: Array of invite IDs (inv_xxx format) to add AddTeamMembersResponse: type: object properties: success: type: boolean data: type: object properties: team_id: type: integer added: type: array items: type: object properties: session_id: type: integer status: type: string enum: [added, already_member, not_found, not_completed] added_count: type: integer skipped_count: type: integer RemoveAllMembersResponse: type: object properties: success: type: boolean data: type: object properties: team_id: type: integer removed_count: type: integer message: type: string RemoveMemberResponse: type: object properties: success: type: boolean data: type: object properties: team_id: type: integer session_id: type: integer removed: type: boolean TeamExportResponse: type: object properties: success: type: boolean data: type: object properties: team_id: type: integer team_name: type: string exported_at: type: string format: date-time member_count: type: integer members: type: array items: $ref: '#/components/schemas/TeamExportMember' TeamExportMember: type: object properties: session_id: type: integer first_name: type: string last_name: type: string email: type: string completed_at: type: string format: date-time dimensions: type: object description: All dimension scores (0-100) additionalProperties: type: number graves_values: type: object description: Graves values (G2-G7) additionalProperties: type: number ProfileListResponse: type: object properties: success: type: boolean data: type: object properties: profiles: type: array items: $ref: '#/components/schemas/ProfileSummary' pagination: type: object properties: total: type: integer limit: type: integer offset: type: integer has_more: type: boolean filters: type: object properties: status: type: string sort: type: string ProfileSummary: type: object properties: session_id: type: integer invite_id: type: string nullable: true candidate: type: object properties: first_name: type: string last_name: type: string name: type: string email: type: string gender: type: string enum: [male, female, diverse] birth_date: type: string format: date nullable: true assessment: type: object properties: type: type: string status: type: string enum: [completed, in_progress] started_at: type: string format: date-time completed_at: type: string format: date-time nullable: true source: type: string enum: [api, manual] description: Whether created via API or Admin Tool results: type: object description: Only present when include_results=true additionalProperties: type: number links: type: object properties: details: type: string results: type: string nullable: true report: type: string nullable: true ProfileDetailResponse: type: object properties: success: type: boolean data: type: object properties: session_id: type: integer invite_id: type: string nullable: true candidate: type: object properties: first_name: type: string last_name: type: string name: type: string email: type: string gender: type: string birth_date: type: string nullable: true assessment: type: object properties: type: type: string status: type: string started_at: type: string completed_at: type: string nullable: true calculation_type: type: string source: type: string enum: [api, manual] results: type: object description: Full dimension results (only for completed) properties: dimensions: type: object graves_values: type: object norm_group: type: string nullable: true teams: type: array items: type: object properties: id: type: integer title: type: string subtitle: type: string links: type: object properties: results_json: type: string nullable: true report_pdf: type: string nullable: true responses: BadRequest: description: Invalid request content: application/json: schema: $ref: '#/components/schemas/Error' Unauthorized: description: Missing or invalid API key content: application/json: schema: $ref: '#/components/schemas/Error' NotFound: description: Resource not found content: application/json: schema: $ref: '#/components/schemas/Error'