openapi: 3.1.0 info: version: 1.0.0 title: Ashby API Key Report API description: Complete public API for accessing resources in your Ashby instance. Includes applications, candidates, jobs, interviews, offers, surveys, custom fields, organization metadata, files, reports, approvals, and webhooks. contact: name: Ashby Support url: https://app.ashbyhq.com/support email: support@ashbyhq.com servers: - url: https://api.ashbyhq.com security: - BasicAuth: [] tags: - name: Report paths: /report.generate: post: summary: report.generate operationId: reportGenerate description: '> ⚠️ Beta > > This endpoint is currently in beta and may change without notice. Generates a new report or polls the status of an existing report generation. **Two-step process:** 1. Call with only `reportId` to start generation → returns `requestId` 2. Poll with both `reportId` and `requestId` every second until `status` is `complete` or `failed` **Example:** ``` // Step 1: Start generation POST /report.generate { "reportId": "abc-123-def-456" } → { "requestId": "rep_result:12345abc", "status": "in_progress", "reportData": null } // Step 2: Poll for results POST /report.generate { "reportId": "abc-123-def-456", "requestId": "rep_result:12345abc" } → { "requestId": "rep_result:12345abc", "status": "complete", "reportData": {...} } ``` **Rate Limiting (Per Organization):** - **Start generation requests** (without `requestId`): 15 requests per minute per organization - **Concurrent limit**: Maximum 3 report operations at once per organization (shared with [`report.synchronous`](https://developers.ashbyhq.com/reference/reportsynchronous)) - **Polling requests** (with `requestId`): Bypass all limits **Usage Notes:** - If you receive a 429 error, your organization has hit its limit - wait and retry or use [`report.synchronous`](https://developers.ashbyhq.com/reference/reportsynchronous) - For synchronous retrieval of existing data, use [`report.synchronous`](https://developers.ashbyhq.com/reference/reportsynchronous) - Use this async endpoint for reports that may exceed 30 seconds **Requires the [`reportsRead`](authentication#permissions-reportgenerate) permission.** ' tags: - Report requestBody: required: true content: application/json: schema: allOf: - $ref: '#/paths/~1report.synchronous/post/requestBody/content/application~1json/schema' - type: object properties: requestId: type: string description: Request ID for polling existing report generation status (optional - only used when polling) examples: start_generation: summary: Standard report request value: reportId: f9e52a51-a075-4116-a7b8-484deba69004 start_generation_no_headers: $ref: '#/paths/~1report.synchronous/post/requestBody/content/application~1json/examples/no_headers_request' poll_generation: summary: Poll generation status value: reportId: f9e52a51-a075-4116-a7b8-484deba69004 requestId: rep_result:12345abc responses: '200': description: Responses for the report.generate endpoint content: application/json: schema: oneOf: - title: Success response allOf: - $ref: '#/paths/~1job.info/post/responses/200/content/application~1json/schema/oneOf/0/allOf/0' - type: object properties: results: type: object properties: requestId: type: string description: Unique identifier for this report generation request status: type: string enum: - complete - failed - in_progress description: Current status of the report generation reportData: anyOf: - type: object properties: data: type: array items: type: array items: oneOf: - type: string - type: number description: Report data rows as arrays of values. When includeHeadersInData is true (default), the first row contains column headers. columnNames: type: array items: type: string description: Column names/headers for the report data. metadata: type: object properties: updatedAt: type: string format: date-time description: When the report data was last updated title: type: string description: Report title reportGeneratedAt: type: string format: date-time description: ISO 8601 timestamp indicating when the report data was generated. Only present when status is complete. cacheExpiresAt: type: string format: date-time description: 'ISO 8601 timestamp indicating when the cached report data will expire (estimated). Calculated as reportGeneratedAt + cache duration (1 hour for successful reports, 15 minutes for failed reports). This is an estimate with typical accuracy within 1 second of actual Redis TTL expiration. Only present when status is complete or failed. ' required: - updatedAt - title required: - data - columnNames - metadata - type: 'null' description: Report data (only present when status is complete) failureReason: type: - string - 'null' description: Error information if report generation failed required: - requestId - status - reportData required: - results - title: Error response $ref: '#/paths/~1report.generate/post/responses/429/content/application~1json/schema' examples: initial_request: summary: Report generation in progress value: success: true results: requestId: rep_result:12345abc status: in_progress reportData: null failureReason: null complete: summary: Completed report with cache metadata description: "When includeHeadersInData=false, the data array would be:\n```\nreportData.data: [\n [ \"Q1 2024\", \"Engineering\", 45 ],\n [ \"Q1 2024\", \"Sales\", 32 ],\n [ \"Q2 2024\", \"Engineering\", 52 ]\n]\n```\n" value: success: true results: requestId: rep_result:12345abc status: complete reportData: data: - - Timeframe - Department - Hired - - Q1 2024 - Engineering - 45 - - Q1 2024 - Sales - 32 - - Q2 2024 - Engineering - 52 columnNames: - Timeframe - Department - Hired metadata: updatedAt: '2024-01-15T10:30:00Z' title: Quarterly Hiring Report reportGeneratedAt: '2024-01-15T14:25:33.123Z' cacheExpiresAt: '2024-01-15T15:25:33.123Z' failed: summary: Failed report generation (timeout or error) value: success: true results: requestId: rep_result:12345abc status: failed reportData: null failureReason: QueryTimeout '429': description: Rate limit or concurrent limit exceeded content: application/json: schema: allOf: - $ref: '#/paths/~1job.info/post/responses/200/content/application~1json/schema/oneOf/0/allOf/0' - title: Error response - type: object required: - errors - errorInfo properties: errors: description: A list of error codes type: array items: type: string deprecated: true errorInfo: description: A single error code and additional error information type: object required: - code properties: code: type: string message: type: string requestId: type: string description: Opaque identifier for the API request, which can be provided to Ashby support to help them diagnose the issue meta: type: object example: success: false errors: - invalid_input errorInfo: code: invalid_input message: Request payload is malformed requestId: 01JSJ8FDK5ZN4XQBZP7DBKK7ZC examples: rate_limit_exceeded: summary: Rate limit exceeded (15 requests per minute per organization) value: success: false errors: - Rate limit exceeded errorInfo: code: rate_limit_exceeded message: Your organization has exceeded the rate limit of 15 report requests per minute. Try again in 60 seconds. requestId: rep_result:12345abc concurrent_limit_exceeded: summary: Concurrent operation limit exceeded (3 maximum per organization) value: success: false errors: - Concurrent limit exceeded errorInfo: code: concurrent_limit_exceeded message: Your organization has reached the maximum of 3 concurrent report operations. Please wait for existing operations to complete or try again in 30 seconds. requestId: rep_result:12345abc /report.synchronous: post: summary: report.synchronous operationId: reportSynchronous description: '> ⚠️ Beta > > This endpoint is currently in beta and may change without notice. Retrieves report data synchronously. **Timeout:** 30 seconds. If a report is timing out, use the asynchronous [`report.generate`](https://developers.ashbyhq.com/reference/reportgenerate) instead. **Rate Limiting (Per Organization):** - **Request limit**: 15 requests per minute per organization - **Concurrent limit**: Maximum 3 report operations at once per organization (shared with [`report.generate`](https://developers.ashbyhq.com/reference/reportgenerate)) - Rate limits are shared with [`report.generate`](https://developers.ashbyhq.com/reference/reportgenerate) for starting new generations **Usage Notes:** - If you receive a 429 error, your organization has hit its limit - wait briefly and retry - For long-running reports, use [`report.generate`](https://developers.ashbyhq.com/reference/reportgenerate) for async processing - Concurrent limit is released when the HTTP request completes **Requires the [`reportsRead`](authentication#permissions-reportsynchronous) permission.** ' tags: - Report requestBody: required: true content: application/json: schema: type: object properties: reportId: allOf: - $ref: '#/paths/~1interviewerPool.addUser/post/requestBody/content/application~1json/schema/properties/userId' - description: The ID of the report includeHeadersInData: type: boolean default: true description: When true (default), column headers are included as the first row in the data array. When false, headers are only in the columnNames property. required: - reportId examples: standard_request: $ref: '#/paths/~1report.generate/post/requestBody/content/application~1json/examples/start_generation' no_headers_request: summary: Request without headers in data value: reportId: f9e52a51-a075-4116-a7b8-484deba69004 includeHeadersInData: false responses: '200': description: Responses for the report.synchronous endpoint content: application/json: schema: oneOf: - title: Success response $ref: '#/paths/~1report.generate/post/responses/200/content/application~1json/schema/oneOf/0' - title: Error response $ref: '#/paths/~1report.generate/post/responses/429/content/application~1json/schema' examples: success_response: $ref: '#/paths/~1report.generate/post/responses/200/content/application~1json/examples/complete' timeout_response: $ref: '#/paths/~1report.generate/post/responses/200/content/application~1json/examples/initial_request' '429': description: Rate limit or concurrent limit exceeded content: application/json: schema: $ref: '#/paths/~1report.generate/post/responses/429/content/application~1json/schema' examples: rate_limit_exceeded: $ref: '#/paths/~1report.generate/post/responses/429/content/application~1json/examples/rate_limit_exceeded' concurrent_limit_exceeded: $ref: '#/paths/~1report.generate/post/responses/429/content/application~1json/examples/concurrent_limit_exceeded' components: securitySchemes: BasicAuth: type: http scheme: basic description: HTTP Basic Auth. Send your Ashby API key as the username and leave the password blank. WebhookSignature: type: apiKey in: header name: Ashby-Signature description: HMAC-SHA256 signature of the webhook payload, used to verify webhook authenticity.