Skip to content

Tax Practice AI - API Specification

Version: 1.1 Last Updated: 2025-12-28 Status: Draft Base URL: https://api.taxpractice.example.com/v1


Table of Contents

  1. Overview
  2. Authentication
  3. Common Patterns
  4. Clients API
  5. Returns API
  6. Documents API
  7. Questions API
  8. Messages API
  9. Invoices API
  10. Engagements API
  11. E-Filing API
  12. Identity Verification API
  13. Webhooks API
  14. Admin API
Document Purpose
DATA_MODEL.md Entity definitions (35+ entities)
PROCESS_FLOWS.md State machines and workflows
SECURITY_DESIGN.md Authentication and authorization details
INTEGRATION_CONTRACTS.md External system specifications

1. Overview

1.1 Design Principles

Principle Implementation
RESTful Resource-based URLs, standard HTTP methods
JSON All request/response bodies are JSON
Versioned URL versioning (/v1/, /v2/)
Consistent Standard response envelopes, error formats
Secure JWT authentication, role-based access
Auditable Correlation IDs for all requests

1.2 URL Structure

https://api.taxpractice.example.com/v1/{resource}/{id}/{sub-resource}

Examples: - GET /v1/clients - List clients - GET /v1/clients/{id} - Get client - GET /v1/clients/{id}/returns - List client's returns - POST /v1/returns/{id}/workflow/transition - Transition workflow state

1.3 HTTP Methods

Method Usage Idempotent
GET Retrieve resources Yes
POST Create resources, actions No
PUT Replace resource Yes
PATCH Partial update No
DELETE Soft delete resource Yes

1.4 Content Types

Direction Content-Type
Request application/json
Response application/json
File upload multipart/form-data
File download application/pdf, image/*, etc.

2. Authentication

2.1 JWT Authentication

Header Format:

Authorization: Bearer <jwt_token>

Token Structure:

{
  "sub": "user-uuid",
  "role": "preparer",
  "email": "user@example.com",
  "client_ids": ["uuid-1"],
  "exp": 1703376000,
  "iat": 1703374200,
  "jti": "unique-token-id"
}

2.2 Authentication Endpoints

POST /v1/auth/login

Staff login with credentials.

Request:

{
  "email": "preparer@firm.com",
  "password": "secure_password"
}

Response (200 - MFA Required):

{
  "status": "mfa_required",
  "mfa_token": "temporary-mfa-token",
  "mfa_methods": ["totp", "webauthn"]
}

POST /v1/auth/mfa/verify

Complete MFA verification.

Request:

{
  "mfa_token": "temporary-mfa-token",
  "code": "123456",
  "method": "totp"
}

Response (200):

{
  "access_token": "eyJhbGciOiJSUzI1NiI...",
  "refresh_token": "refresh-token-value",
  "expires_in": 1800,
  "token_type": "Bearer"
}

POST /v1/auth/refresh

Refresh access token.

Request:

{
  "refresh_token": "refresh-token-value"
}

Response (200):

{
  "access_token": "eyJhbGciOiJSUzI1NiI...",
  "expires_in": 1800,
  "token_type": "Bearer"
}

POST /v1/auth/logout

Invalidate current session.

Response (204): No content

2.3 Client Portal Authentication

POST /v1/portal/auth/magic-link

Request magic link for client login.

Request:

{
  "email": "client@example.com"
}

Response (200):

{
  "message": "If this email is registered, a login link has been sent."
}

POST /v1/portal/auth/verify-link

Verify magic link token.

Request:

{
  "token": "magic-link-token-from-email"
}

Response (200):

{
  "access_token": "eyJhbGciOiJSUzI1NiI...",
  "expires_in": 3600,
  "token_type": "Bearer"
}


3. Common Patterns

3.1 Request Headers

Header Required Description
Authorization Yes (except auth endpoints) Bearer JWT token
Content-Type Yes (POST/PUT/PATCH) application/json
X-Correlation-ID No Client-generated trace ID
X-Idempotency-Key No (recommended for POST) Prevents duplicate operations

3.2 Response Envelope

Success Response:

{
  "data": { ... },
  "meta": {
    "request_id": "req-uuid",
    "correlation_id": "client-trace-id",
    "timestamp": "2024-12-23T10:30:00Z"
  }
}

List Response:

{
  "data": [ ... ],
  "meta": {
    "request_id": "req-uuid",
    "correlation_id": "client-trace-id",
    "timestamp": "2024-12-23T10:30:00Z"
  },
  "pagination": {
    "cursor": "next-cursor-value",
    "has_more": true,
    "total_count": 150
  }
}

3.3 Error Response (RFC 7807)

{
  "type": "https://api.taxpractice.example.com/errors/validation",
  "title": "Validation Error",
  "status": 400,
  "detail": "One or more fields failed validation",
  "instance": "/v1/clients",
  "errors": [
    {
      "field": "email",
      "code": "invalid_format",
      "message": "Email must be a valid email address"
    }
  ],
  "meta": {
    "request_id": "req-uuid",
    "correlation_id": "client-trace-id",
    "timestamp": "2024-12-23T10:30:00Z"
  }
}

3.4 HTTP Status Codes

Code Meaning Usage
200 OK Successful GET, PUT, PATCH
201 Created Successful POST creating resource
204 No Content Successful DELETE
400 Bad Request Validation error
401 Unauthorized Missing or invalid authentication
403 Forbidden Insufficient permissions
404 Not Found Resource doesn't exist
409 Conflict State conflict (e.g., duplicate)
422 Unprocessable Entity Business rule violation
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Unexpected server error

3.5 Pagination (Cursor-Based)

Request:

GET /v1/clients?limit=25&cursor=eyJpZCI6ImFiYzEyMyJ9

Parameters:

Parameter Type Default Max Description
limit integer 25 100 Items per page
cursor string null - Opaque cursor from previous response

Response:

{
  "data": [...],
  "pagination": {
    "cursor": "eyJpZCI6Inh5ejc4OSJ9",
    "has_more": true,
    "total_count": 150
  }
}

3.6 Filtering and Sorting

Query Parameters:

GET /v1/returns?status=in_prep&tax_year=2024&sort=-created_at&fields=id,status,client_id

Parameter Description Example
{field} Filter by field value status=in_prep
{field}__gte Greater than or equal created_at__gte=2024-01-01
{field}__lte Less than or equal amount__lte=10000
{field}__in In list status__in=in_prep,ready_for_review
sort Sort field (prefix - for desc) sort=-created_at
fields Sparse fieldset fields=id,status,client_id

3.7 Rate Limiting

Headers:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1703380000

Limits:

Endpoint Type Limit Window
Standard 1000 requests 5 minutes
Auth 10 requests 1 minute
File upload 100 requests 5 minutes
Webhooks 500 requests 1 minute

4. Clients API

4.1 List Clients

GET /v1/clients

Permissions: Admin, EA/CPA, Reviewer (all), Preparer (assigned only)

Query Parameters:

Parameter Type Description
status string Filter by status (active, inactive, closed)
client_type string Filter by type (individual, business, trust, nonprofit)
assigned_preparer_id uuid Filter by assigned preparer
search string Search name, email, account_number

Response (200):

{
  "data": [
    {
      "id": "uuid",
      "account_number": "C-2024-00001",
      "client_type": "individual",
      "name": "John Smith",
      "email": "john.smith@example.com",
      "phone": "+1-555-123-4567",
      "status": "active",
      "assigned_preparer_id": "preparer-uuid",
      "created_at": "2024-01-15T10:30:00Z",
      "updated_at": "2024-12-20T14:22:00Z"
    }
  ],
  "pagination": {
    "cursor": "eyJpZCI6ImFiYzEyMyJ9",
    "has_more": true,
    "total_count": 150
  }
}

4.2 Get Client

GET /v1/clients/{id}

Permissions: Admin, EA/CPA, Reviewer, Preparer (if assigned), Client (own only)

Response (200):

{
  "data": {
    "id": "uuid",
    "account_number": "C-2024-00001",
    "client_type": "individual",
    "name": "John Smith",
    "email": "john.smith@example.com",
    "phone": "+1-555-123-4567",
    "address": {
      "street1": "123 Main St",
      "street2": "Apt 4B",
      "city": "San Francisco",
      "state": "CA",
      "zip": "94102"
    },
    "ssn_last4": "1234",
    "date_of_birth": "1980-05-15",
    "status": "active",
    "identity_verification_status": "verified",
    "assigned_preparer_id": "preparer-uuid",
    "contacts": [
      {
        "id": "contact-uuid",
        "name": "Jane Smith",
        "relationship": "spouse",
        "email": "jane.smith@example.com",
        "phone": "+1-555-234-5678",
        "is_primary": false
      }
    ],
    "created_at": "2024-01-15T10:30:00Z",
    "updated_at": "2024-12-20T14:22:00Z"
  }
}

4.3 Create Client

POST /v1/clients

Permissions: Admin, EA/CPA, Reviewer, Preparer

Request:

{
  "client_type": "individual",
  "name": "John Smith",
  "email": "john.smith@example.com",
  "phone": "+1-555-123-4567",
  "address": {
    "street1": "123 Main St",
    "city": "San Francisco",
    "state": "CA",
    "zip": "94102"
  },
  "ssn": "123-45-6789",
  "date_of_birth": "1980-05-15"
}

Response (201):

{
  "data": {
    "id": "new-client-uuid",
    "account_number": "C-2024-00152",
    ...
  }
}

4.4 Update Client

PATCH /v1/clients/{id}

Permissions: Admin, EA/CPA, Reviewer, Preparer (if assigned)

Request:

{
  "phone": "+1-555-999-8888",
  "address": {
    "street1": "456 New Street"
  }
}

Response (200): Updated client object

4.5 Delete Client (Soft)

DELETE /v1/clients/{id}

Permissions: Admin only

Response (204): No content

4.6 Client Contacts

List Contacts

GET /v1/clients/{id}/contacts

Add Contact

POST /v1/clients/{id}/contacts

Request:

{
  "name": "Jane Smith",
  "relationship": "spouse",
  "email": "jane.smith@example.com",
  "phone": "+1-555-234-5678",
  "is_primary": false
}

Update Contact

PATCH /v1/clients/{client_id}/contacts/{contact_id}

Delete Contact

DELETE /v1/clients/{client_id}/contacts/{contact_id}


5. Returns API

5.1 List Returns

GET /v1/returns

Permissions: Admin, EA/CPA, Reviewer (all), Preparer (assigned only), Client (own only)

Query Parameters:

Parameter Type Description
client_id uuid Filter by client
tax_year integer Filter by tax year
status string Filter by workflow status
return_type string Filter by type (1040, 1120S, etc.)
assigned_preparer_id uuid Filter by preparer

Response (200):

{
  "data": [
    {
      "id": "return-uuid",
      "client_id": "client-uuid",
      "client_name": "John Smith",
      "tax_year": 2024,
      "return_type": "1040",
      "filing_status": "married_joint",
      "status": "in_prep",
      "progress_percentage": 50,
      "assigned_preparer_id": "preparer-uuid",
      "assigned_reviewer_id": null,
      "extension_filed": false,
      "created_at": "2024-01-20T09:00:00Z",
      "updated_at": "2024-12-22T16:45:00Z"
    }
  ]
}

5.2 Get Return

GET /v1/returns/{id}

Response (200):

{
  "data": {
    "id": "return-uuid",
    "client_id": "client-uuid",
    "tax_year": 2024,
    "return_type": "1040",
    "filing_status": "married_joint",
    "status": "in_prep",
    "progress_percentage": 50,
    "assigned_preparer_id": "preparer-uuid",
    "assigned_reviewer_id": null,
    "extension_filed": false,
    "extension_date": null,
    "due_date": "2025-04-15",
    "priority": "normal",
    "estimated_refund": 2500.00,
    "estimated_tax_due": null,
    "federal_status": "in_progress",
    "state_filings": [
      {
        "state": "CA",
        "status": "in_progress"
      }
    ],
    "workflow_history": [
      {
        "from_status": "ready_for_prep",
        "to_status": "in_prep",
        "transitioned_at": "2024-12-22T10:00:00Z",
        "transitioned_by": "preparer-uuid",
        "notes": "Starting preparation"
      }
    ],
    "created_at": "2024-01-20T09:00:00Z",
    "updated_at": "2024-12-22T16:45:00Z"
  }
}

5.3 Create Return

POST /v1/returns

Permissions: Admin, EA/CPA, Reviewer, Preparer

Request:

{
  "client_id": "client-uuid",
  "tax_year": 2024,
  "return_type": "1040",
  "filing_status": "married_joint",
  "assigned_preparer_id": "preparer-uuid"
}

Response (201): Created return object

5.4 Update Return

PATCH /v1/returns/{id}

Permissions: Admin, EA/CPA, Reviewer, Preparer (if assigned)

Request:

{
  "filing_status": "single",
  "priority": "rush"
}

Response (200): Updated return object

5.5 Delete Return (Soft)

DELETE /v1/returns/{id}

Permissions: Admin, EA/CPA

Notes: Soft delete only - sets deleted_at timestamp. Returns with filed status cannot be deleted.

Response (204): No content

5.6 Workflow Transition

POST /v1/returns/{id}/workflow/transition

Permissions: Varies by transition (see PROCESS_FLOWS.md)

Request:

{
  "action": "submit_for_review",
  "notes": "Ready for reviewer examination"
}

Valid Actions:

Action From Status To Status Required Role
start_prep ready_for_prep ai_analysis Preparer
complete_ai_analysis ai_analysis in_prep System
request_client_info in_prep pending_client_response Preparer
client_responded pending_client_response in_prep System
submit_for_review in_prep ready_for_review Preparer
start_review ready_for_review in_review Reviewer
request_revisions in_review revisions_needed Reviewer
approve in_review approved Reviewer/EA
send_for_signature approved pending_signature System
signature_received pending_signature ready_to_file System
transmit ready_to_file filed System
mark_accepted filed accepted System
mark_rejected filed rejected System
restart_after_rejection rejected in_prep Preparer/EA
complete accepted complete System

Response (200):

{
  "data": {
    "id": "return-uuid",
    "status": "ready_for_review",
    "previous_status": "in_prep",
    "transitioned_at": "2024-12-23T11:00:00Z"
  }
}

5.7 Get Workflow State

GET /v1/returns/{id}/workflow/state

Returns the current workflow state with full history.

Response (200):

{
  "data": {
    "current_status": "in_review",
    "entered_at": "2024-12-23T10:00:00Z",
    "days_in_status": 1,
    "assigned_to": "reviewer-uuid",
    "history": [
      {
        "from_status": "in_prep",
        "to_status": "ready_for_review",
        "transitioned_at": "2024-12-22T16:00:00Z",
        "transitioned_by": "preparer-uuid",
        "notes": "Ready for review"
      },
      {
        "from_status": "ready_for_review",
        "to_status": "in_review",
        "transitioned_at": "2024-12-23T10:00:00Z",
        "transitioned_by": "reviewer-uuid",
        "notes": "Starting review"
      }
    ]
  }
}

5.8 AI Analysis

POST /v1/returns/{id}/ai/analyze

Permissions: Admin, EA/CPA, Reviewer, Preparer

Triggers AI analysis of the return.

Request:

{
  "analysis_type": "comprehensive",
  "include_prior_year_comparison": true
}

Response (202):

{
  "data": {
    "analysis_id": "analysis-uuid",
    "status": "processing",
    "estimated_completion": "2024-12-23T11:05:00Z"
  }
}

5.9 Get AI Analysis

GET /v1/returns/{id}/ai/analysis/{analysis_id}

Response (200):

{
  "data": {
    "id": "analysis-uuid",
    "status": "completed",
    "completed_at": "2024-12-23T11:03:00Z",
    "findings": [
      {
        "type": "missing_document",
        "severity": "high",
        "description": "1099-B from brokerage not found",
        "recommendation": "Request brokerage statement from client"
      },
      {
        "type": "prior_year_variance",
        "severity": "medium",
        "description": "Interest income increased 150% from prior year",
        "recommendation": "Verify with client - may indicate new accounts"
      }
    ],
    "suggested_questions": [
      {
        "id": "q-uuid-1",
        "question": "Did you open any new investment accounts in 2024?",
        "context": "Interest income significantly higher than prior year"
      }
    ]
  }
}


6. Documents API

6.1 List Documents

GET /v1/documents

Query Parameters:

Parameter Type Description
client_id uuid Filter by client
return_id uuid Filter by return
tax_year integer Filter by tax year
document_type string Filter by type (w2, 1099_div, etc.)
status string Filter by status

Response (200):

{
  "data": [
    {
      "id": "doc-uuid",
      "client_id": "client-uuid",
      "return_id": "return-uuid",
      "tax_year": 2024,
      "document_type": "W-2",
      "document_subtype": null,
      "filename": "W2_Employer_2024.pdf",
      "file_size": 125000,
      "mime_type": "application/pdf",
      "status": "extracted",
      "extraction_confidence": 0.95,
      "source": "client_upload",
      "uploaded_at": "2024-12-20T10:00:00Z",
      "processed_at": "2024-12-20T10:02:00Z"
    }
  ]
}

6.2 Get Document

GET /v1/documents/{id}

Response (200):

{
  "data": {
    "id": "doc-uuid",
    "client_id": "client-uuid",
    "return_id": "return-uuid",
    "tax_year": 2024,
    "document_type": "W-2",
    "filename": "W2_Employer_2024.pdf",
    "file_size": 125000,
    "mime_type": "application/pdf",
    "status": "extracted",
    "extraction": {
      "id": "extraction-uuid",
      "status": "verified",
      "overall_confidence": 0.95,
      "fields": [
        {
          "field_name": "employer_name",
          "value": "Acme Corporation",
          "confidence": 0.99,
          "needs_review": false
        },
        {
          "field_name": "wages",
          "value": "75000.00",
          "confidence": 0.97,
          "needs_review": false
        },
        {
          "field_name": "federal_withholding",
          "value": "12500.00",
          "confidence": 0.85,
          "needs_review": true
        }
      ]
    },
    "uploaded_at": "2024-12-20T10:00:00Z"
  }
}

6.3 Upload Document

POST /v1/documents

Content-Type: multipart/form-data

Form Fields:

Field Type Required Description
file file Yes Document file
client_id uuid Yes Client ID
return_id uuid No Return ID (optional)
tax_year integer Yes Tax year
document_type string No Type hint (auto-classified if omitted)

Response (201):

{
  "data": {
    "id": "new-doc-uuid",
    "status": "processing",
    "filename": "W2_2024.pdf",
    "uploaded_at": "2024-12-23T11:30:00Z"
  }
}

6.4 Download Document

GET /v1/documents/{id}/download

Response (200): Binary file with appropriate Content-Type

6.5 Update Document Metadata

PATCH /v1/documents/{id}

Permissions: Admin, EA/CPA, Reviewer, Preparer

Request:

{
  "document_type": "W-2",
  "tax_year": 2024,
  "return_id": "return-uuid"
}

Response (200): Updated document object

6.6 Delete Document (Soft)

DELETE /v1/documents/{id}

Permissions: Admin, EA/CPA

Notes: Soft delete only. Documents linked to filed returns cannot be deleted.

Response (204): No content

6.7 Update Extraction Field

PATCH /v1/documents/{doc_id}/extraction/fields/{field_id}

Permissions: Admin, EA/CPA, Reviewer, Preparer

Request:

{
  "value": "12750.00",
  "verified": true
}

Response (200): Updated field object

6.8 Delete Extraction

DELETE /v1/documents/{id}/extraction

Permissions: Admin, EA/CPA

Deletes extraction data for a document, allowing re-extraction.

Response (204): No content

6.9 Document Checklist

GET /v1/returns/{id}/documents/checklist

Returns expected documents based on prior year and current submissions.

Response (200):

{
  "data": {
    "expected": [
      {
        "document_type": "W-2",
        "description": "W-2 from Acme Corporation",
        "status": "received",
        "document_id": "doc-uuid"
      },
      {
        "document_type": "1099-DIV",
        "description": "1099-DIV from Fidelity (based on prior year)",
        "status": "missing",
        "document_id": null
      }
    ],
    "unexpected": [
      {
        "document_type": "1099-INT",
        "description": "1099-INT from New Bank",
        "document_id": "doc-uuid-2"
      }
    ]
  }
}

6.10 Pending Documents (Upload-First Flow)

Upload documents before creating a client. Documents are stored in a pending state until assigned.

Upload Pending Document

POST /v1/pending-documents

Content-Type: multipart/form-data

Form Fields:

Field Type Required Description
file file Yes Document file
batch_id string Yes Batch identifier for grouping

Response (201):

{
  "data": {
    "id": "pending-doc-uuid",
    "upload_batch_id": "batch-123",
    "original_filename": "W2_2024.pdf",
    "file_size_bytes": 125000,
    "mime_type": "application/pdf",
    "document_type": "W-2",
    "tax_year": 2024,
    "s3_key": "pending/batch-123/W2_2024.pdf",
    "uploaded_at": "2024-12-20T10:00:00Z"
  }
}

List Pending Batches

GET /v1/pending-documents/batches

Response (200):

{
  "data": [
    {
      "batch_id": "batch-123",
      "document_count": 3,
      "uploaded_at": "2024-12-20T10:00:00Z",
      "documents": [
        {
          "id": "pending-doc-uuid",
          "original_filename": "W2_2024.pdf",
          "document_type": "W-2",
          "tax_year": 2024
        }
      ]
    }
  ]
}

Create Client from Batch

POST /v1/batch/{batch_id}/create-client

Creates a client, return, and moves pending documents to the new return.

Request:

{
  "first_name": "John",
  "last_name": "Smith",
  "email": "john.smith@example.com",
  "phone": "+1-555-123-4567",
  "tax_year": 2024,
  "return_type": "individual"
}

Response (201):

{
  "data": {
    "client": {
      "id": "client-uuid",
      "account_number": "20241220-0001",
      "first_name": "John",
      "last_name": "Smith"
    },
    "return": {
      "id": "return-uuid",
      "tax_year": 2024,
      "return_type": "individual",
      "status": "intake"
    },
    "documents_assigned": 3
  }
}


7. Questions API

Client questions generated by AI or preparer.

7.1 List Questions

GET /v1/returns/{id}/questions

Query Parameters:

Parameter Type Description
status string Filter by status (pending, answered, skipped)

Response (200):

{
  "data": [
    {
      "id": "question-uuid",
      "return_id": "return-uuid",
      "question_text": "Did you sell any stocks or investments in 2024?",
      "context": "We noticed interest income but no capital gains reported",
      "priority": "high",
      "status": "pending",
      "source": "ai_generated",
      "created_by": null,
      "created_at": "2024-12-22T14:00:00Z",
      "answered_at": null,
      "answer_text": null
    }
  ]
}

7.2 Get Question

GET /v1/returns/{id}/questions/{question_id}

Response (200):

{
  "data": {
    "id": "question-uuid",
    "return_id": "return-uuid",
    "question_text": "Did you work from home in 2024?",
    "context": "For home office deduction",
    "category": "deduction_clarification",
    "source": "ai_generated",
    "status": "answered",
    "created_at": "2024-12-22T14:00:00Z",
    "answered_at": "2024-12-22T15:30:00Z",
    "answer_text": "Yes, 3 days per week on average",
    "answer_attachments": []
  }
}

7.3 Create Question

POST /v1/returns/{id}/questions

Permissions: Admin, EA/CPA, Reviewer, Preparer

Request:

{
  "question_text": "Please confirm your home office square footage",
  "context": "For home office deduction calculation",
  "priority": "medium"
}

7.4 Answer Question (Client)

POST /v1/returns/{id}/questions/{question_id}/answer

Permissions: Client (own return)

Request:

{
  "answer_text": "The home office is 150 square feet",
  "attachments": ["doc-uuid-if-any"]
}

7.5 Skip Question

POST /v1/returns/{id}/questions/{question_id}/skip

Permissions: Admin, EA/CPA, Reviewer, Preparer

Request:

{
  "reason": "Confirmed via phone call with client"
}


8. Messages API

Portal messaging between staff and clients.

8.1 List Messages

GET /v1/clients/{id}/messages

Query Parameters:

Parameter Type Description
return_id uuid Filter by return
direction string inbound, outbound, or both

Response (200):

{
  "data": [
    {
      "id": "message-uuid",
      "client_id": "client-uuid",
      "return_id": "return-uuid",
      "direction": "outbound",
      "sender_type": "staff",
      "sender_id": "preparer-uuid",
      "sender_name": "Sarah Preparer",
      "subject": "Missing document needed",
      "body": "Hello John, we need your 1099-B from...",
      "read_at": "2024-12-22T16:30:00Z",
      "created_at": "2024-12-22T14:00:00Z"
    }
  ]
}

8.2 Send Message

POST /v1/clients/{id}/messages

Permissions: Admin, EA/CPA, Reviewer, Preparer (if assigned), Client (own)

Request:

{
  "return_id": "return-uuid",
  "subject": "Question about your return",
  "body": "Hello, I wanted to follow up on...",
  "notify_email": true
}

8.3 Mark as Read

POST /v1/clients/{id}/messages/{message_id}/read

Response (200):

{
  "data": {
    "id": "message-uuid",
    "read_at": "2024-12-23T12:00:00Z"
  }
}


9. Invoices API

9.1 List Invoices

GET /v1/invoices

Query Parameters:

Parameter Type Description
client_id uuid Filter by client
return_id uuid Filter by return
status string Filter by status (draft, sent, paid, overdue)

Response (200):

{
  "data": [
    {
      "id": "invoice-uuid",
      "invoice_number": "INV-2024-00042",
      "client_id": "client-uuid",
      "return_id": "return-uuid",
      "status": "sent",
      "amount": 450.00,
      "tax": 0.00,
      "total": 450.00,
      "amount_paid": 0.00,
      "amount_due": 450.00,
      "due_date": "2025-01-15",
      "payment_link": "https://pay.stripe.com/...",
      "line_items": [
        {
          "description": "2024 Individual Tax Return (1040)",
          "quantity": 1,
          "unit_price": 400.00,
          "amount": 400.00
        },
        {
          "description": "Schedule C - Business Income",
          "quantity": 1,
          "unit_price": 50.00,
          "amount": 50.00
        }
      ],
      "created_at": "2024-12-22T10:00:00Z",
      "sent_at": "2024-12-22T10:05:00Z"
    }
  ]
}

9.2 Get Invoice

GET /v1/invoices/{id}

Response (200):

{
  "data": {
    "id": "invoice-uuid",
    "client_id": "client-uuid",
    "return_id": "return-uuid",
    "invoice_number": "INV-2024-0001",
    "status": "sent",
    "total_amount": 450.00,
    "amount_paid": 0.00,
    "balance_due": 450.00,
    "due_date": "2025-01-15",
    "line_items": [
      {
        "description": "2024 Individual Tax Return (1040)",
        "quantity": 1,
        "unit_price": 400.00,
        "amount": 400.00
      },
      {
        "description": "Schedule C - Business Income",
        "quantity": 1,
        "unit_price": 50.00,
        "amount": 50.00
      }
    ],
    "payments": [],
    "created_at": "2024-12-22T10:00:00Z",
    "sent_at": "2024-12-22T10:05:00Z"
  }
}

9.3 Create Invoice

POST /v1/invoices

Permissions: Admin, EA/CPA

Request:

{
  "client_id": "client-uuid",
  "return_id": "return-uuid",
  "due_date": "2025-01-15",
  "line_items": [
    {
      "description": "2024 Individual Tax Return (1040)",
      "quantity": 1,
      "unit_price": 400.00
    }
  ]
}

Response (201): Created invoice object

9.4 Update Invoice

PATCH /v1/invoices/{id}

Permissions: Admin, EA/CPA

Notes: Only draft invoices can be updated. Sent invoices must be voided and recreated.

Request:

{
  "due_date": "2025-01-31",
  "line_items": [
    {
      "description": "2024 Individual Tax Return (1040)",
      "quantity": 1,
      "unit_price": 450.00
    }
  ]
}

Response (200): Updated invoice object

9.5 Send Invoice

POST /v1/invoices/{id}/send

Permissions: Admin, EA/CPA

Sends invoice to client via email with payment link (draft invoices only).

Response (200):

{
  "data": {
    "id": "invoice-uuid",
    "status": "sent",
    "sent_at": "2024-12-23T12:30:00Z",
    "payment_link": "https://pay.stripe.com/..."
  }
}

9.6 Record Payment

POST /v1/invoices/{id}/payments

Request:

{
  "amount": 450.00,
  "payment_method": "credit_card",
  "stripe_payment_intent_id": "pi_xxxxx"
}

9.7 List Payments

GET /v1/invoices/{id}/payments

Response (200):

{
  "data": [
    {
      "id": "payment-uuid",
      "invoice_id": "invoice-uuid",
      "amount": 450.00,
      "payment_method": "credit_card",
      "status": "completed",
      "stripe_payment_intent_id": "pi_xxxxx",
      "processed_at": "2024-12-23T14:00:00Z",
      "created_at": "2024-12-23T14:00:00Z"
    }
  ],
  "meta": {
    "total_paid": 450.00,
    "balance_due": 0.00
  }
}


10. Engagements API

10.1 List Engagements

GET /v1/engagements

Query Parameters:

Parameter Type Description
client_id uuid Filter by client
tax_year integer Filter by tax year
status string Filter by status

10.2 Get Engagement

GET /v1/engagements/{id}

Permissions: Admin, EA/CPA, Reviewer, Preparer (if assigned to client)

Response (200):

{
  "data": {
    "id": "engagement-uuid",
    "client_id": "client-uuid",
    "tax_year": 2024,
    "engagement_type": "tax_prep",
    "services": ["1040", "schedule_c"],
    "status": "signed",
    "fee_structure": {
      "type": "fixed",
      "base_fee": 400.00,
      "additional_forms": 50.00
    },
    "signed_at": "2024-01-15T10:30:00Z",
    "document_url": "/v1/engagements/engagement-uuid/document",
    "created_at": "2024-01-10T09:00:00Z"
  }
}

10.3 Create Engagement

POST /v1/engagements

Permissions: Admin, EA/CPA, Reviewer

Request:

{
  "client_id": "client-uuid",
  "tax_year": 2024,
  "engagement_type": "tax_prep",
  "services": ["1040", "schedule_c"],
  "fee_structure": {
    "type": "fixed",
    "base_fee": 400.00,
    "additional_forms": 50.00
  }
}

10.4 Update Engagement

PATCH /v1/engagements/{id}

Permissions: Admin, EA/CPA, Reviewer

Guard Conditions: - Status must not be signed (engagement already executed)

Request:

{
  "services": ["1040", "schedule_c", "schedule_e"],
  "fee_structure": {
    "type": "fixed",
    "base_fee": 500.00,
    "additional_forms": 50.00
  }
}

Response (200): Updated engagement object

10.5 Delete Engagement

DELETE /v1/engagements/{id}

Permissions: Admin, EA/CPA

Guard Conditions: - Status must be draft (cannot delete signed engagements)

Response (204): No content

10.6 Send for Signature

POST /v1/engagements/{id}/send

Generates engagement letter and sends via Google Workspace for signature.

Response (200):

{
  "data": {
    "id": "engagement-uuid",
    "status": "pending_signature",
    "signature_request_id": "google-sig-uuid",
    "sent_at": "2024-12-23T13:00:00Z"
  }
}

10.7 Get Signed Document

GET /v1/engagements/{id}/document

Returns signed engagement letter PDF.

IRS Form 7216 consent for disclosure of tax return information to third parties.

List Consents

GET /v1/clients/{id}/consents

Response (200):

{
  "data": [
    {
      "id": "consent-uuid",
      "client_id": "client-uuid",
      "tax_year": 2024,
      "consent_scope": "SurePrep document processing",
      "status": "signed",
      "created_at": "2024-01-15T10:00:00Z",
      "signed_at": "2024-01-15T10:05:00Z",
      "expires_at": "2025-01-15T10:05:00Z"
    }
  ]
}

POST /v1/clients/{id}/consents

Permissions: Admin, EA/CPA, Reviewer

Request:

{
  "tax_year": 2024,
  "consent_scope": "SurePrep document processing",
  "third_party_name": "SurePrep LLC",
  "disclosure_purpose": "Document OCR and data extraction for tax preparation"
}

Response (201): Created consent object with status pending

GET /v1/consents/{id}

Response (200): Full consent object including signature details

Send for Signature

POST /v1/consents/{id}/send

Sends Form 7216 consent to client via Google Workspace for e-signature.

Response (200):

{
  "data": {
    "id": "consent-uuid",
    "status": "sent",
    "signature_request_id": "google-sig-uuid",
    "sent_at": "2024-01-15T10:00:00Z"
  }
}

POST /v1/consents/{id}/revoke

Permissions: Admin, EA/CPA

Revokes an active consent. Creates audit trail entry.

Response (200):

{
  "data": {
    "id": "consent-uuid",
    "status": "revoked",
    "revoked_at": "2024-06-15T14:00:00Z",
    "revoked_by": "user-uuid"
  }
}


11. E-Filing API

11.1 List E-File Transmissions

GET /v1/returns/{id}/efiling

Response (200):

{
  "data": [
    {
      "id": "transmission-uuid",
      "return_id": "return-uuid",
      "jurisdiction": "federal",
      "status": "accepted",
      "transmitted_at": "2024-12-23T09:00:00Z",
      "acknowledged_at": "2024-12-23T12:30:00Z",
      "confirmation_number": "IRS123456789",
      "acceptance_date": "2024-12-23"
    },
    {
      "id": "transmission-uuid-2",
      "return_id": "return-uuid",
      "jurisdiction": "CA",
      "status": "pending",
      "transmitted_at": "2024-12-23T09:00:00Z",
      "acknowledged_at": null
    }
  ]
}

11.2 Get Transmission

GET /v1/returns/{id}/efiling/{transmission_id}

Response (200):

{
  "data": {
    "id": "transmission-uuid",
    "return_id": "return-uuid",
    "jurisdiction": "federal",
    "transmission_type": "original",
    "status": "transmitted",
    "transmitted_at": "2024-12-23T09:00:00Z",
    "acknowledgement": {
      "id": "ack-uuid",
      "ack_type": "accepted",
      "confirmation_number": "IRS123456789",
      "received_at": "2024-12-23T12:30:00Z"
    },
    "rejection": null
  }
}

11.3 Transmit Return

POST /v1/returns/{id}/efiling/transmit

Permissions: Admin, EA/CPA

Guard Conditions: - Return status must be ready_to_file - Signed Form 8879 must be on file - All required forms must be complete

Request:

{
  "jurisdictions": ["federal", "CA"]
}

Response (202):

{
  "data": {
    "transmissions": [
      {
        "id": "transmission-uuid",
        "jurisdiction": "federal",
        "status": "transmitting"
      },
      {
        "id": "transmission-uuid-2",
        "jurisdiction": "CA",
        "status": "transmitting"
      }
    ]
  }
}

11.4 Get Rejection Details

GET /v1/returns/{id}/efiling/{transmission_id}/rejections

Response (200):

{
  "data": {
    "transmission_id": "transmission-uuid",
    "jurisdiction": "federal",
    "rejections": [
      {
        "id": "rejection-uuid",
        "error_code": "IND-031-04",
        "category": "data_mismatch",
        "description": "SSN/Name mismatch with SSA records",
        "resolution_guidance": "Verify taxpayer SSN and name match Social Security card exactly",
        "auto_correctable": false,
        "created_at": "2024-12-23T12:35:00Z"
      }
    ]
  }
}

11.5 Resubmit After Rejection

POST /v1/returns/{id}/efiling/{transmission_id}/resubmit

Permissions: Admin, EA/CPA

Request:

{
  "notes": "Corrected SSN format"
}

11.6 Estimated Tax Payments

Manage quarterly estimated tax payments for clients.

List Estimated Payments

GET /v1/returns/{id}/estimated-payments

Response (200):

{
  "data": [
    {
      "id": "payment-uuid",
      "return_id": "return-uuid",
      "quarter": 1,
      "due_date": "2025-04-15",
      "federal_amount": 5000.00,
      "state_amount": 1500.00,
      "status": "scheduled",
      "reminder_sent": false
    },
    {
      "id": "payment-uuid-2",
      "quarter": 2,
      "due_date": "2025-06-15",
      "federal_amount": 5000.00,
      "state_amount": 1500.00,
      "status": "scheduled",
      "reminder_sent": false
    }
  ]
}

Create Estimated Payment Schedule

POST /v1/returns/{id}/estimated-payments

Permissions: Admin, EA/CPA, Preparer

Request:

{
  "tax_year": 2025,
  "federal_annual": 20000.00,
  "state_annual": 6000.00,
  "payment_method": "equal_quarterly"
}

Response (201): Created payment schedule with 4 quarterly payments

Update Payment

PATCH /v1/estimated-payments/{id}

Request:

{
  "federal_amount": 6000.00,
  "status": "confirmed_paid"
}

Response (200): Updated payment object

Send Reminder

POST /v1/estimated-payments/{id}/remind

Sends reminder to client about upcoming estimated tax payment.

Request:

{
  "reminder_type": "14_day",
  "channels": ["email", "sms"]
}

Response (200):

{
  "data": {
    "id": "payment-uuid",
    "reminder_sent": true,
    "reminder_sent_at": "2024-04-01T10:00:00Z",
    "reminder_type": "14_day"
  }
}

Mark Payment Confirmed

POST /v1/estimated-payments/{id}/confirm

Client confirms payment was made.

Request:

{
  "confirmation_number": "IRS-12345",
  "payment_date": "2025-04-14",
  "payment_method": "ach"
}

Response (200): Updated payment with status confirmed_paid

Delete Estimated Payment

DELETE /v1/estimated-payments/{id}

Permissions: Admin, EA/CPA

Guard Conditions: - Payment status must not be confirmed_paid

Cancels a scheduled estimated tax payment.

Response (204): No content


12. Identity Verification API

12.1 Initiate Verification

POST /v1/clients/{id}/identity/verify

Request:

{
  "tier": 2,
  "methods": ["email", "phone", "government_id"]
}

Response (201):

{
  "data": {
    "verification_id": "verification-uuid",
    "status": "pending",
    "current_step": "email",
    "steps": [
      {"step": "email", "status": "pending"},
      {"step": "phone", "status": "pending"},
      {"step": "government_id", "status": "pending"}
    ]
  }
}

12.2 Verify Email

POST /v1/identity/{verification_id}/email/verify

Request:

{
  "code": "123456"
}

12.3 Verify Phone

POST /v1/identity/{verification_id}/phone/send

Request:

{
  "method": "sms"
}

POST /v1/identity/{verification_id}/phone/verify

Request:

{
  "code": "654321"
}

12.4 Submit Government ID

POST /v1/identity/{verification_id}/government-id

Redirects to Persona or returns embed URL.

Response (200):

{
  "data": {
    "persona_inquiry_url": "https://withpersona.com/verify?inquiry-id=...",
    "expires_at": "2024-12-23T14:00:00Z"
  }
}

12.5 Get Verification Status

GET /v1/identity/{verification_id}

Response (200):

{
  "data": {
    "verification_id": "verification-uuid",
    "client_id": "client-uuid",
    "tier": 2,
    "status": "completed",
    "confidence_score": 0.92,
    "completed_at": "2024-12-23T13:45:00Z",
    "steps": [
      {"step": "email", "status": "completed"},
      {"step": "phone", "status": "completed"},
      {"step": "government_id", "status": "completed", "confidence": 0.92}
    ]
  }
}

12.6 Schedule Video Verification (Tier 3)

POST /v1/identity/{verification_id}/video/schedule

Request:

{
  "preferred_times": [
    "2024-12-24T10:00:00Z",
    "2024-12-24T14:00:00Z"
  ]
}

Response (200):

{
  "data": {
    "session_id": "meet-session-uuid",
    "scheduled_time": "2024-12-24T10:00:00Z",
    "meet_link": "https://meet.google.com/xxx-xxxx-xxx",
    "calendar_invite_sent": true
  }
}


13. Webhooks API

13.1 Webhook Endpoints (Inbound)

The system receives webhooks from external providers.

Stripe Webhooks

POST /v1/webhooks/stripe

Headers:

Stripe-Signature: t=...,v1=...

Events Handled: - payment_intent.succeeded - payment_intent.payment_failed - checkout.session.completed

Persona Webhooks

POST /v1/webhooks/persona

Headers:

Persona-Signature: ...

Events Handled: - inquiry.completed - inquiry.failed - inquiry.expired

SmartVault Webhooks

POST /v1/webhooks/smartvault

Events Handled: - document.uploaded - folder.created

SurePrep Webhooks

POST /v1/webhooks/sureprep

Events Handled: - binder.submitted - Binder submitted for processing - binder.processing_complete - OCR/extraction finished - binder.verification_complete - Manual verification done - document.uploaded - Document added to binder - extraction.ready - Extracted data available

Google Workspace Webhooks

POST /v1/webhooks/google

Events Handled: - signature.completed - signature.declined - calendar.event.updated

E-Filing Webhooks

POST /v1/webhooks/efiling

Events Handled: - transmission.accepted - Return accepted by IRS/state - transmission.rejected - Return rejected with error codes - transmission.pending - Return awaiting acknowledgment

13.2 Webhook Signature Verification

All inbound webhooks are verified:

def verify_stripe_webhook(payload: bytes, signature: str) -> bool:
    """Verify Stripe webhook signature using HMAC."""
    pass

def verify_persona_webhook(payload: bytes, signature: str) -> bool:
    """Verify Persona webhook signature."""
    pass

13.3 Webhook Delivery (Outbound)

Future: System can send webhooks to external systems.

POST /v1/admin/webhooks

Request:

{
  "url": "https://partner.example.com/webhook",
  "events": ["return.status.changed", "document.uploaded"],
  "secret": "webhook-signing-secret"
}


14. Admin API

14.1 Users

List Users

GET /v1/admin/users

Permissions: Admin only

Create User

POST /v1/admin/users

Request:

{
  "email": "newpreparer@firm.com",
  "full_name": "New Preparer",
  "role": "preparer",
  "ptin": "P12345678"
}

Update User

PATCH /v1/admin/users/{id}

Deactivate User

POST /v1/admin/users/{id}/deactivate

14.2 System Configuration

Get Configuration

GET /v1/admin/config

Update Configuration

PATCH /v1/admin/config

Request:

{
  "session_timeout_minutes": 30,
  "mfa_required": true,
  "failed_login_lockout_attempts": 5
}

14.3 Audit Logs

Query Audit Logs

GET /v1/admin/audit

Query Parameters:

Parameter Type Description
user_id uuid Filter by user
client_id uuid Filter by client
event_type string Filter by event type
start_date datetime Start of date range
end_date datetime End of date range

Export Audit Logs

POST /v1/admin/audit/export

Request:

{
  "start_date": "2024-01-01T00:00:00Z",
  "end_date": "2024-12-31T23:59:59Z",
  "format": "json",
  "filters": {
    "client_id": "client-uuid"
  }
}

Response (202):

{
  "data": {
    "export_id": "export-uuid",
    "status": "processing",
    "estimated_size_mb": 50
  }
}

14.4 System Health

Health Check

GET /v1/health

No authentication required

Response (200):

{
  "status": "healthy",
  "version": "1.0.0",
  "timestamp": "2024-12-23T15:00:00Z"
}

Detailed Health

GET /v1/admin/health/detailed

Permissions: Admin only

Response (200):

{
  "status": "healthy",
  "components": {
    "database": {"status": "healthy", "latency_ms": 5},
    "redis": {"status": "healthy", "latency_ms": 2},
    "s3": {"status": "healthy"},
    "bedrock": {"status": "healthy"},
    "stripe": {"status": "healthy"},
    "persona": {"status": "healthy"}
  }
}


Appendix A: Enum Values

Client Type

  • individual
  • business
  • trust
  • nonprofit

Return Type

  • 1040 - Individual
  • 1120 - C Corporation
  • 1120S - S Corporation
  • 1065 - Partnership
  • 1041 - Trust/Estate
  • 990 - Nonprofit
  • 706 - Gift Tax Return
  • 709 - Generation Skipping Transfer Tax

Filing Status

  • single
  • married_joint
  • married_separate
  • head_of_household
  • qualifying_widow

Return Status (Workflow)

  • intake
  • documents_pending
  • ready_for_prep
  • ai_analysis
  • in_prep
  • pending_client_response
  • ready_for_review
  • in_review
  • revisions_needed
  • approved
  • pending_signature
  • ready_to_file
  • filed
  • accepted
  • rejected
  • complete
  • needs_review

Document Type

  • W-2 - Wage and Tax Statement
  • W-2G - Gambling Winnings
  • 1099-INT - Interest Income
  • 1099-DIV - Dividends and Distributions
  • 1099-B - Broker Transactions
  • 1099-R - Retirement Distributions
  • 1099-MISC - Miscellaneous Income
  • 1099-NEC - Nonemployee Compensation
  • 1099-K - Payment Card Transactions
  • 1099-G - Government Payments
  • SSA-1099 - Social Security Benefits
  • K-1_1065 - Schedule K-1 (Partnership)
  • K-1_1120S - Schedule K-1 (S Corporation)
  • K-1_1041 - Schedule K-1 (Trust/Estate)
  • 1098 - Mortgage Interest
  • 1098-E - Student Loan Interest
  • 1098-T - Tuition Statement
  • BANK_STATEMENT - Bank Statement
  • BROKERAGE_STATEMENT - Brokerage Statement
  • PROPERTY_TAX - Property Tax Statement
  • ENGAGEMENT_LETTER - Engagement Letter
  • FORM_8879 - IRS e-file Signature Authorization
  • FORM_7216 - Consent for Disclosure
  • DRAFT_RETURN - Draft Tax Return
  • FINAL_RETURN - Final Tax Return
  • EFILE_CONFIRMATION - E-file Confirmation
  • ID_DOCUMENT - Identity Document
  • OTHER - Other Document

User Role (Staff)

  • admin
  • ea_cpa
  • reviewer
  • preparer

Note: Clients authenticate via tiered identity verification and receive JWT tokens with client_id claims. They do not have a database user role. See SECURITY_DESIGN.md Section 2.2.


Appendix B: Internal Resources

The following database tables are internal resources accessed only through related API endpoints or internal services. They do not have dedicated REST endpoints.

Resource Table Access Method
Preparer Notes preparer_notes Included in GET /v1/returns/{id} response for staff
Workflow State workflow_state Via GET /v1/returns/{id}/workflow/state
Workflow History workflow_history Included in workflow state response
Extracted Fields extracted_field Included in GET /v1/documents/{id} extraction data
Audit Log audit_log Admin-only via GET /v1/admin/audit-logs
PTIN Records ptin_record Admin-only via GET /v1/admin/users/{id}

Preparer Notes: Staff can add, view, and update notes on returns via the return detail endpoint. Notes are stored in preparer_notes table with return_id, document_id (optional), and note_text fields.

GET /v1/returns/{id}  → includes preparer_notes array
PATCH /v1/returns/{id} → can update notes via nested object

Document History

Version Date Author Changes
1.0 2024-12-23 Don McCarty Initial API specification

This document defines the REST API for Tax Practice AI. Implementation should follow these specifications exactly to ensure consistency across clients.