openapi: 3.0.3 info: title: TinyTax Formation Agent API version: '1.0' description: | REST API for formation agents to submit dormant company filings to HMRC (CT600) and Companies House (accounts). ## Overview The TinyTax API enables you to automate dormant company filings at scale. Submit CT600 nil returns to HMRC and dormant accounts to Companies House with minimal required fields - we auto-derive company details from Companies House. ## Authentication All API requests require an API key passed in the `X-API-Key` header: ``` X-API-Key: tt_live_k1a2b3c4d5e6_s9x8y7z6w5v4u3t2r1q0p9o8n7m6l5k4 ``` Get your API key from the [API Dashboard](/profile/api). ## Idempotency All POST requests require an `Idempotency-Key` header to prevent duplicate filings: ``` Idempotency-Key: your-unique-request-id ``` If you retry a request with the same idempotency key and request body, you'll receive the original response. Keys expire after 24 hours. ## Sandbox Mode Use test API keys (`tt_test_...`) to try the API without making real filings. Sandbox mode: - **Full validation** - same validation as live mode - **No real filings** - no HMRC/CH calls, no database records - **Deterministic outcomes** - use magic company numbers to test different scenarios - **No charges** - sandbox requests don't deduct from your balance ### Magic Test Company Numbers | Company Number | Outcome | Polling | |----------------|---------|---------| | `00000001` | Accepted | Poll required | | `00000002` | Rejected (UTR mismatch) | Poll required | | `00000003` | Rejected (period already filed) | Poll required | | `00000004` | Error (gateway timeout) | Poll required | | `00000005` | Accepted | Immediate | | `SC000001` | Scotland - Accepted | Poll required | | `SC000002` | Scotland - Rejected (company dissolved) | Poll required | | `NI000001` | N. Ireland - Accepted | Poll required | | `NI000002` | N. Ireland - Rejected (auth code invalid) | Poll required | Sandbox filing IDs use format `fil_test_{type}_{company}_{hash}` and are fully deterministic. Poll `GET /filings/{id}` to get the final outcome. See the [Sandbox Guide](/developers/sandbox) for detailed testing instructions. ## Rate Limits | Limit | Default | |-------|---------| | Per minute | 60 requests | | Per day | 1,000 requests | Rate limit headers are included in all responses: - `X-RateLimit-Limit-Minute` - `X-RateLimit-Remaining-Minute` - `X-RateLimit-Limit-Day` - `X-RateLimit-Remaining-Day` ## Smart Defaults The API automatically derives most data from Companies House: - Company name and entity type - Period start date (from ARD or incorporation) - First active director name - Share capital (from IN01, defaults to £100) - Prior year figures (from filing history) This means a dormant accounts filing requires just **3 fields**: `company_number`, `period_end`, and `credentials`. contact: name: TinyTax Support email: hello@tinytax.co.uk url: https://tinytax.co.uk/support x-logo: url: /assets/brand/logos/logo_primary.png altText: TinyTax servers: - url: https://tinytax.co.uk/api/v1 description: Production (use tt_test_ keys for sandbox mode) tags: - name: Filings description: Submit and manage filings - name: Documents description: Download generated documents - name: Health description: API health check security: - ApiKeyAuth: [] paths: /health: get: operationId: getHealth summary: Health check description: Returns API status. No authentication required. tags: - Health security: [] responses: '200': description: API is healthy content: application/json: schema: type: object properties: status: type: string example: ok version: type: string example: '1.0' timestamp: type: string format: date-time /filings: get: operationId: listFilings summary: List filings description: Returns a paginated list of your filings, ordered by creation date (newest first). tags: - Filings parameters: - name: status in: query description: Filter by status schema: type: string enum: [pending, submitted, accepted, rejected, error] - name: type in: query description: Filter by filing type schema: type: string enum: [ct600, accounts] - name: company_number in: query description: Filter by company number schema: type: string - name: limit in: query description: Number of results per page (max 100) schema: type: integer default: 20 maximum: 100 - name: offset in: query description: Number of results to skip schema: type: integer default: 0 responses: '200': description: List of filings content: application/json: schema: $ref: '#/components/schemas/FilingsList' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/RateLimited' /filings/ct600: post: operationId: submitCT600 summary: Submit dormant CT600 description: | Submit a dormant CT600 nil return to HMRC. **Minimal request:** Only `company_number`, `utr`, `period_end`, and `credentials` are required. All other fields are auto-derived from Companies House. **Extended periods:** Accounting periods over 12 months are automatically split into two CT600 submissions (first 12 months, then remainder). You'll receive a single `filing_id` with `period_split: true`. **Async processing:** Returns immediately with status `submitted`. Poll `GET /filings/{id}` for final status. tags: - Filings parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CT600Request' examples: minimal: summary: Minimal request (recommended) value: company_number: '12345678' utr: '1234567890' period_end: '2024-12-31' credentials: government_gateway_id: '123456789012' government_gateway_password: 'password123' with_overrides: summary: With optional overrides value: company_number: '12345678' utr: '1234567890' period_end: '2024-12-31' company: name: 'Override Name Ltd' period: start: '2024-01-01' declarant: name: 'Jane Smith' status: 'Company Secretary' credentials: government_gateway_id: '123456789012' government_gateway_password: 'password123' responses: '202': description: Filing submitted successfully content: application/json: schema: $ref: '#/components/schemas/CT600Response' '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/InsufficientBalance' '409': $ref: '#/components/responses/IdempotencyConflict' '429': $ref: '#/components/responses/RateLimited' '502': $ref: '#/components/responses/GatewayError' /filings/accounts: post: operationId: submitAccounts summary: Submit dormant accounts description: | Submit dormant accounts to Companies House. **Minimal request:** Only `company_number`, `period_end`, and `credentials` are required. All other fields are auto-derived from Companies House. **Async processing:** Returns immediately with status `submitted`. Poll `GET /filings/{id}` for final status. tags: - Filings parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AccountsRequest' examples: minimal: summary: Minimal request (recommended) value: company_number: '12345678' period_end: '2024-12-31' credentials: company_auth_code: 'ABC123' with_overrides: summary: With optional overrides value: company_number: '12345678' period_end: '2024-12-31' company: name: 'Override Name Ltd' entity_type: 'private-limited-guarant-nsc' period: start: '2024-01-01' is_first_year: true approval: date: '2025-01-15' director_name: 'Jane Smith' director_position: 'Director' balance_sheet: share_capital: 1 cash: 1 creditors: 0 profit_loss_account: 0 credentials: company_auth_code: 'ABC123' responses: '202': description: Filing submitted successfully content: application/json: schema: $ref: '#/components/schemas/AccountsResponse' '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/InsufficientBalance' '409': $ref: '#/components/responses/IdempotencyConflict' '429': $ref: '#/components/responses/RateLimited' '502': $ref: '#/components/responses/GatewayError' /filings/{filing_id}: get: operationId: getFiling summary: Get filing status description: | Returns the current status of a filing. **Polling:** After submission, poll this endpoint to check for final status. Recommended interval: every 30 seconds for first 5 minutes, then every 5 minutes. **Split periods:** For extended period CT600s, the response includes a `parts` array with individual HMRC submission statuses. tags: - Filings parameters: - name: filing_id in: path required: true description: Filing ID (e.g., `fil_abc123def456`) schema: type: string responses: '200': description: Filing details content: application/json: schema: $ref: '#/components/schemas/FilingStatus' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/FilingNotFound' /filings/{filing_id}/documents: get: operationId: listDocuments summary: List available documents description: | Returns a list of documents available for download. Documents are only available after the filing reaches `accepted` status. tags: - Documents parameters: - name: filing_id in: path required: true schema: type: string responses: '200': description: List of documents content: application/json: schema: $ref: '#/components/schemas/DocumentsList' '400': description: Filing not complete content: application/json: schema: $ref: '#/components/schemas/Error' example: success: false error: code: FILING_NOT_COMPLETE message: Filing not yet accepted, documents not generated '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/FilingNotFound' /filings/{filing_id}/documents/{type}: get: operationId: downloadDocument summary: Download document description: | Downloads a specific document. **Document types:** | Type | Description | Available For | |------|-------------|---------------| | `ct600_pdf` | CT600 form as PDF | CT600 filings | | `ct600_xml` | Raw HMRC submission XML | CT600 filings | | `ixbrl_accounts` | iXBRL accounts document | Accounts filings | | `accounts_pdf` | Human-readable accounts PDF | Accounts filings | tags: - Documents parameters: - name: filing_id in: path required: true schema: type: string - name: type in: path required: true schema: type: string enum: [ct600_pdf, ct600_xml, ixbrl_accounts, accounts_pdf] responses: '200': description: Document file content: application/pdf: schema: type: string format: binary application/xml: schema: type: string format: binary application/xhtml+xml: schema: type: string format: binary '400': description: Filing not complete content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '404': description: Document not found content: application/json: schema: $ref: '#/components/schemas/Error' example: success: false error: code: DOCUMENT_NOT_FOUND message: Document type not available for this filing components: securitySchemes: ApiKeyAuth: type: apiKey in: header name: X-API-Key description: | API key in format: `tt_{env}_{key_id}_{secret}` **Key types:** - `tt_test_...` - Sandbox mode (no real filings, deterministic responses) - `tt_live_...` - Production mode (real HMRC/CH submissions) Example: `tt_live_k1a2b3c4d5e6_s9x8y7z6w5v4u3t2r1q0p9o8n7m6l5k4` parameters: IdempotencyKey: name: Idempotency-Key in: header required: true description: Unique key for request deduplication (max 64 characters) schema: type: string maxLength: 64 example: 'req_2025-01-15_12345678_ct600' schemas: CT600Request: type: object required: - company_number - utr - period_end - credentials properties: company_number: type: string pattern: '^[A-Z0-9]{8}$' description: 8-character company registration number example: '12345678' utr: type: string pattern: '^\d{10}$' description: 10-digit Unique Taxpayer Reference example: '1234567890' period_end: type: string format: date description: Accounting period end date (YYYY-MM-DD) example: '2024-12-31' company: type: object description: Override company details (auto-derived from CH if not provided) properties: name: type: string description: Company name period: type: object description: Override period details (auto-derived if not provided) properties: start: type: string format: date description: Period start date declarant: type: object description: Override declarant details (first director used if not provided) properties: name: type: string description: Name of person signing declaration status: type: string enum: [Director, Company Secretary, Agent] description: Position of declarant credentials: type: object required: - government_gateway_id - government_gateway_password properties: government_gateway_id: type: string description: Government Gateway user ID example: '123456789012' government_gateway_password: type: string format: password description: Government Gateway password example: 'password123' AccountsRequest: type: object required: - company_number - period_end - credentials properties: company_number: type: string pattern: '^[A-Z0-9]{8}$' description: 8-character company registration number example: '12345678' period_end: type: string format: date description: Accounting period end date (YYYY-MM-DD) example: '2024-12-31' company: type: object description: Override company details properties: name: type: string entity_type: type: string description: Companies House entity type code period: type: object properties: start: type: string format: date is_first_year: type: boolean description: Whether this is the first accounting period approval: type: object description: Override approval details properties: date: type: string format: date description: Date accounts were approved director_name: type: string director_position: type: string balance_sheet: type: object description: Override balance sheet values (must balance if provided) properties: share_capital: type: number cash: type: number creditors: type: number profit_loss_account: type: number credentials: type: object required: - company_auth_code properties: company_auth_code: type: string pattern: '^[A-Z0-9]{6}$' description: 6-character company authentication code example: 'ABC123' CT600Response: type: object properties: success: type: boolean example: true data: type: object properties: filing_id: type: string example: 'fil_abc123def456' status: type: string enum: [pending, submitted, accepted, rejected, error] example: submitted hmrc_correlation_id: type: string example: 'A1B2C3D4E5F6' period_split: type: boolean description: True if period was split into multiple submissions example: false parts: type: array description: Only present if period_split is true items: $ref: '#/components/schemas/FilingPart' submitted_at: type: string format: date-time derived_values: type: object description: Values auto-derived from Companies House properties: company_name: type: string period_start: type: string format: date is_first_year: type: boolean declarant_name: type: string declarant_status: type: string request_id: type: string format: uuid AccountsResponse: type: object properties: success: type: boolean example: true data: type: object properties: filing_id: type: string example: 'fil_xyz789abc012' status: type: string enum: [pending, submitted, accepted, rejected, error] example: submitted ch_submission_number: type: string example: 'CH-2025-001234' submitted_at: type: string format: date-time derived_values: type: object properties: company_name: type: string entity_type: type: string period_start: type: string format: date is_first_year: type: boolean director_name: type: string approval_date: type: string format: date share_capital: type: number cash: type: number request_id: type: string format: uuid FilingStatus: type: object properties: success: type: boolean data: type: object properties: filing_id: type: string filing_type: type: string enum: [ct600, accounts] company_number: type: string company_name: type: string period: type: object properties: start: type: string format: date end: type: string format: date status: type: string enum: [pending, submitted, accepted, rejected, error] period_split: type: boolean parts: type: array items: $ref: '#/components/schemas/FilingPart' hmrc_status: type: string description: For CT600 filings (single period) hmrc_correlation_id: type: string hmrc_iru_number: type: string description: IRmark unique reference (on acceptance) ch_status: type: string description: For accounts filings ch_submission_number: type: string error: type: object description: Present if status is rejected or error properties: code: type: string message: type: string created_at: type: string format: date-time updated_at: type: string format: date-time FilingPart: type: object properties: part_number: type: integer example: 1 period: type: object properties: start: type: string format: date end: type: string format: date hmrc_status: type: string enum: [pending, submitted, polling, accepted, rejected, error] hmrc_correlation_id: type: string hmrc_iru_number: type: string FilingsList: type: object properties: success: type: boolean data: type: object properties: filings: type: array items: $ref: '#/components/schemas/FilingSummary' pagination: type: object properties: total: type: integer limit: type: integer offset: type: integer has_more: type: boolean FilingSummary: type: object properties: filing_id: type: string filing_type: type: string enum: [ct600, accounts] company_number: type: string company_name: type: string period_end: type: string format: date status: type: string created_at: type: string format: date-time DocumentsList: type: object properties: success: type: boolean data: type: object properties: filing_id: type: string documents: type: array items: type: object properties: type: type: string enum: [ct600_pdf, ct600_xml, ixbrl_accounts, accounts_pdf] name: type: string size_bytes: type: integer generated_at: type: string format: date-time Error: type: object properties: success: type: boolean example: false error: type: object properties: code: type: string message: type: string details: type: array items: type: object properties: field: type: string message: type: string request_id: type: string format: uuid responses: Unauthorized: description: Authentication failed content: application/json: schema: $ref: '#/components/schemas/Error' examples: missing_key: summary: Missing API key value: success: false error: code: AUTH_REQUIRED message: Missing X-API-Key header invalid_key: summary: Invalid API key value: success: false error: code: INVALID_KEY message: Invalid or expired API key ValidationError: description: Request validation failed content: application/json: schema: $ref: '#/components/schemas/Error' example: success: false error: code: VALIDATION_ERROR message: Request validation failed details: - field: utr message: UTR must be exactly 10 digits request_id: '550e8400-e29b-41d4-a716-446655440000' InsufficientBalance: description: Insufficient account balance content: application/json: schema: $ref: '#/components/schemas/Error' example: success: false error: code: INSUFFICIENT_BALANCE message: Insufficient balance. Please top up your account. details: - field: balance message: 'Required: £20.00, Available: £5.00' request_id: '550e8400-e29b-41d4-a716-446655440000' IdempotencyConflict: description: Idempotency key conflict content: application/json: schema: $ref: '#/components/schemas/Error' example: success: false error: code: IDEMPOTENCY_KEY_CONFLICT message: This idempotency key was used with a different request body request_id: '550e8400-e29b-41d4-a716-446655440000' RateLimited: description: Rate limit exceeded headers: Retry-After: schema: type: integer description: Seconds to wait before retrying X-RateLimit-Remaining-Minute: schema: type: integer content: application/json: schema: $ref: '#/components/schemas/Error' example: success: false error: code: RATE_LIMIT_EXCEEDED message: Too many requests. Please wait before retrying. request_id: '550e8400-e29b-41d4-a716-446655440000' FilingNotFound: description: Filing not found content: application/json: schema: $ref: '#/components/schemas/Error' example: success: false error: code: FILING_NOT_FOUND message: Filing not found or not owned by this API key GatewayError: description: External service error headers: Retry-After: schema: type: integer description: Suggested retry delay in seconds content: application/json: schema: $ref: '#/components/schemas/Error' examples: hmrc_unavailable: summary: HMRC unavailable value: success: false error: code: HMRC_UNAVAILABLE message: HMRC service temporarily unavailable request_id: '550e8400-e29b-41d4-a716-446655440000' ch_unavailable: summary: Companies House unavailable value: success: false error: code: CH_UNAVAILABLE message: Companies House service temporarily unavailable request_id: '550e8400-e29b-41d4-a716-446655440000' hmrc_auth_failed: summary: HMRC credentials invalid value: success: false error: code: HMRC_AUTH_FAILED message: Government Gateway credentials invalid request_id: '550e8400-e29b-41d4-a716-446655440000'