{
  "openapi": "3.1.0",
  "info": {
    "title": "TimeFlov API",
    "version": "v1",
    "description": "Read-only access to your TimeFlov projects, clients, hours, customer invoices and expenses. Every endpoint returns JSON and sees only your own company."
  },
  "servers": [
    {
      "url": "https://api.timeflov.com"
    }
  ],
  "externalDocs": {
    "description": "API reference",
    "url": "https://api.timeflov.com"
  },
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "Projects",
      "description": "Every project in your company with its billing terms. Rates and prices exclude VAT."
    },
    {
      "name": "Clients",
      "description": "Your clients and how they are invoiced. Clients have no `updated_at`, so read the whole list each time."
    },
    {
      "name": "Time entries",
      "description": "Hours reported on your projects, by your team and by subcontractors. Hours appear as soon as they are saved, before the week is submitted or approved."
    },
    {
      "name": "Customer invoices",
      "description": "Invoices and credit notes to your clients. `total_amount` includes VAT."
    },
    {
      "name": "Expenses",
      "description": "Expense reports with their lines. Amounts include VAT."
    }
  ],
  "paths": {
    "/v1/projects": {
      "get": {
        "operationId": "listProjects",
        "summary": "List projects",
        "description": "Every project in your company with its billing terms. Rates and prices exclude VAT. Needs a key with the `read:projects` scope.",
        "tags": [
          "Projects"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/cursor"
          },
          {
            "$ref": "#/components/parameters/updated_since"
          }
        ],
        "responses": {
          "200": {
            "description": "One page of results, ordered by id.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectList"
                },
                "example": {
                  "data": [
                    {
                      "id": "5f0c2a9e-41d7-4b8e-9a51-0d6c3e2f7b10",
                      "client_id": "a3e91f04-6c2b-4f55-8d0e-7b19c4d2e6a8",
                      "name": "Data platform rollout",
                      "description": "Phase 2: ingestion and reporting",
                      "status": "active",
                      "project_type": "time_material",
                      "approval_state": "approved",
                      "budget_hours": 640,
                      "used_hours": 412.5,
                      "hourly_rate": 1250,
                      "fixed_price": null,
                      "retainer_amount": null,
                      "retainer_period": null,
                      "retainer_start_date": null,
                      "is_billable": true,
                      "start_date": "2026-02-02",
                      "end_date": "2026-12-18",
                      "created_at": "2026-01-20T09:14:02.381104+00:00",
                      "updated_at": "2026-10-13T14:22:07.512930+00:00"
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/clients": {
      "get": {
        "operationId": "listClients",
        "summary": "List clients",
        "description": "Your clients and how they are invoiced. Clients have no `updated_at`, so read the whole list each time. Needs a key with the `read:clients` scope.",
        "tags": [
          "Clients"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "One page of results, ordered by id.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientList"
                },
                "example": {
                  "data": [
                    {
                      "id": "a3e91f04-6c2b-4f55-8d0e-7b19c4d2e6a8",
                      "name": "Nordvik Energi AB",
                      "org_number": "556677-8899",
                      "contact_name": "Karin Lund",
                      "contact_email": "karin.lund@nordvik.example",
                      "address": "Hamngatan 12",
                      "city": "Stockholm",
                      "zip_code": "111 47",
                      "country": "SE",
                      "payment_terms": 30,
                      "currency": "SEK",
                      "invoice_email": "invoices@nordvik.example",
                      "vat_treatment": "domestic",
                      "vat_number": "SE556677889901",
                      "is_active": true,
                      "created_at": "2025-11-04T13:40:51.006217+00:00"
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/time_entries": {
      "get": {
        "operationId": "listTimeEntries",
        "summary": "List time entries",
        "description": "Hours reported on your projects, by your team and by subcontractors. Hours appear as soon as they are saved, before the week is submitted or approved. Needs a key with the `read:time_entries` scope.",
        "tags": [
          "Time entries"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/cursor"
          },
          {
            "$ref": "#/components/parameters/updated_since"
          }
        ],
        "responses": {
          "200": {
            "description": "One page of results, ordered by id.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimeEntryList"
                },
                "example": {
                  "data": [
                    {
                      "id": "e41a7c92-3b5d-4f08-96c1-8a2d4e6f0b73",
                      "timesheet_id": "c7d2e5b1-9f34-4a60-b8e2-1d5f7a3c9e04",
                      "user_id": "2b8f6d13-0e7a-4c95-a1d4-6f3e9b2c8a57",
                      "project_id": "5f0c2a9e-41d7-4b8e-9a51-0d6c3e2f7b10",
                      "vendor_id": null,
                      "date": "2026-10-12",
                      "hours": 7.5,
                      "billable": true,
                      "description": "Pipeline tests for the meter feed",
                      "task": "Development",
                      "invoiced_line_id": null,
                      "created_at": "2026-10-12T16:05:33.719402+00:00",
                      "updated_at": "2026-10-12T16:05:33.719402+00:00"
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/customer_invoices": {
      "get": {
        "operationId": "listCustomerInvoices",
        "summary": "List customer invoices",
        "description": "Invoices and credit notes to your clients. `total_amount` includes VAT. Needs a key with the `read:customer_invoices` scope.",
        "tags": [
          "Customer invoices"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/cursor"
          },
          {
            "$ref": "#/components/parameters/updated_since"
          }
        ],
        "responses": {
          "200": {
            "description": "One page of results, ordered by id.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerInvoiceList"
                },
                "example": {
                  "data": [
                    {
                      "id": "9d3b1f68-27c4-4e9a-b05d-3c8e1a7f6d42",
                      "client_id": "a3e91f04-6c2b-4f55-8d0e-7b19c4d2e6a8",
                      "invoice_number": "INV-2026-0142",
                      "status": "sent",
                      "invoice_date": "2026-10-01",
                      "due_date": "2026-10-31",
                      "total_amount": 156250,
                      "vat_amount": 31250,
                      "currency": "SEK",
                      "exchange_rate": 1,
                      "payment_terms": 30,
                      "sent_at": "2026-10-01T08:02:11.204918+00:00",
                      "paid_at": null,
                      "credited_invoice_id": null,
                      "vat_treatment": "domestic",
                      "delivery_status": "delivered",
                      "created_at": "2026-09-30T15:48:20.118352+00:00",
                      "updated_at": "2026-10-01T08:02:11.204918+00:00"
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/expenses": {
      "get": {
        "operationId": "listExpenses",
        "summary": "List expense reports",
        "description": "Expense reports with their lines. Amounts include VAT. Needs a key with the `read:expenses` scope.",
        "tags": [
          "Expenses"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/cursor"
          },
          {
            "$ref": "#/components/parameters/updated_since"
          }
        ],
        "responses": {
          "200": {
            "description": "One page of results, ordered by id.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExpenseReportList"
                },
                "example": {
                  "data": [
                    {
                      "id": "0a6e4c2f-8b1d-4f39-a7e5-2c9d1b3f6e84",
                      "user_id": "2b8f6d13-0e7a-4c95-a1d4-6f3e9b2c8a57",
                      "title": "Client workshop in Gothenburg",
                      "status": "approved",
                      "total_amount": 1840,
                      "currency": "SEK",
                      "submitted_at": "2026-10-09T07:31:45.660128+00:00",
                      "approved_at": "2026-10-10T10:12:03.090551+00:00",
                      "paid_at": null,
                      "created_at": "2026-10-08T19:20:14.538770+00:00",
                      "updated_at": "2026-10-10T10:12:03.090551+00:00",
                      "lines": [
                        {
                          "id": "f2c9b7e4-1a6d-4e05-b8c3-7d4a2f9e1b65",
                          "project_id": "5f0c2a9e-41d7-4b8e-9a51-0d6c3e2f7b10",
                          "expense_type": "receipt",
                          "description": "Train Stockholm to Gothenburg",
                          "amount": 1840,
                          "vat_amount": 104.15,
                          "currency": "SEK",
                          "date": "2026-10-08",
                          "is_billable": true,
                          "is_wellness": false,
                          "mileage_km": null,
                          "invoiced_line_id": null
                        }
                      ]
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "A company API key, created under Admin, API keys. It starts with tf_live_."
      }
    },
    "parameters": {
      "limit": {
        "name": "limit",
        "in": "query",
        "description": "Rows per page, 1 to 200.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 200,
          "default": 100
        }
      },
      "cursor": {
        "name": "cursor",
        "in": "query",
        "description": "The next_cursor from the previous page.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "updated_since": {
        "name": "updated_since",
        "in": "query",
        "description": "Only rows changed at or after this time (ISO 8601).",
        "schema": {
          "type": "string",
          "format": "date-time"
        }
      }
    },
    "headers": {
      "X-RateLimit-Limit": {
        "description": "Requests allowed per clock minute for this key.",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Remaining": {
        "description": "Requests left in this minute.",
        "schema": {
          "type": "integer"
        }
      },
      "Retry-After": {
        "description": "Seconds until the next minute starts.",
        "schema": {
          "type": "integer"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "A query parameter is not valid. `bad_cursor`: `cursor` is not an id from `next_cursor`. `bad_limit`: `limit` is not a whole number between 1 and 200. `bad_updated_since`: `updated_since` is not an ISO 8601 time, or the resource does not support it.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "The key is not valid. `invalid_key`: The key is missing, malformed, unknown, revoked or expired.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "PaymentRequired": {
        "description": "The company's plan or subscription does not include the API. `plan_required`: The company's plan does not include the API. `subscription_inactive`: The company's subscription has lapsed.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The key does not carry the scope for this resource. `scope_missing`: The key may not read this resource.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "More than 600 requests this minute. `rate_limited`: Too many requests this minute. Wait the seconds in `Retry-After`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/Retry-After"
          }
        }
      },
      "ServerError": {
        "description": "The read failed. `read_failed`: The read failed. Retry shortly.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error",
          "code"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "A sentence for people. The wording may change."
          },
          "code": {
            "type": "string",
            "enum": [
              "method_not_allowed",
              "invalid_key",
              "rate_limited",
              "plan_required",
              "subscription_inactive",
              "unknown_resource",
              "scope_missing",
              "bad_cursor",
              "bad_limit",
              "bad_updated_since",
              "read_failed"
            ],
            "description": "Stable. Build on the code, not the sentence."
          }
        }
      },
      "Project": {
        "type": "object",
        "description": "Every project in your company with its billing terms. Rates and prices exclude VAT.",
        "required": [
          "id",
          "client_id",
          "name",
          "description",
          "status",
          "project_type",
          "approval_state",
          "budget_hours",
          "used_hours",
          "hourly_rate",
          "fixed_price",
          "retainer_amount",
          "retainer_period",
          "retainer_start_date",
          "is_billable",
          "start_date",
          "end_date",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The project's id.",
            "examples": [
              "5f0c2a9e-41d7-4b8e-9a51-0d6c3e2f7b10"
            ]
          },
          "client_id": {
            "type": "string",
            "format": "uuid",
            "description": "The client the project belongs to, an id from `clients`.",
            "examples": [
              "a3e91f04-6c2b-4f55-8d0e-7b19c4d2e6a8"
            ]
          },
          "name": {
            "type": "string",
            "description": "The project's name.",
            "examples": [
              "Data platform rollout"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free text about the project.",
            "examples": [
              "Phase 2: ingestion and reporting"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "on_hold",
              "completed",
              "archived"
            ],
            "description": "Where the project is in its life.",
            "examples": [
              "active"
            ]
          },
          "project_type": {
            "type": "string",
            "enum": [
              "time_material",
              "fixed_price",
              "retainer"
            ],
            "description": "How the project is billed: by the hour, at a fixed price, or as a recurring fee.",
            "examples": [
              "time_material"
            ]
          },
          "approval_state": {
            "type": "string",
            "enum": [
              "approved",
              "pending",
              "rejected"
            ],
            "description": "Whether the project has been approved.",
            "examples": [
              "approved"
            ]
          },
          "budget_hours": {
            "type": "number",
            "description": "Hours budgeted for the project.",
            "examples": [
              640
            ]
          },
          "used_hours": {
            "type": "number",
            "description": "Hours reported on the project so far.",
            "examples": [
              412.5
            ]
          },
          "hourly_rate": {
            "type": "number",
            "description": "The project's default hourly billing rate. A price list or a team member's own rate takes precedence when set.",
            "examples": [
              1250
            ]
          },
          "fixed_price": {
            "type": [
              "number",
              "null"
            ],
            "description": "The agreed price, on a fixed-price project.",
            "examples": [
              null
            ]
          },
          "retainer_amount": {
            "type": [
              "number",
              "null"
            ],
            "description": "The fee per period, on a retainer project.",
            "examples": [
              null
            ]
          },
          "retainer_period": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "monthly",
              "quarterly",
              null
            ],
            "description": "How often a retainer is billed.",
            "examples": [
              null
            ]
          },
          "retainer_start_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "The first day of the first retainer period.",
            "examples": [
              null
            ]
          },
          "is_billable": {
            "type": "boolean",
            "description": "Whether time on the project is billed to the client.",
            "examples": [
              true
            ]
          },
          "start_date": {
            "type": "string",
            "format": "date",
            "description": "The project's first day.",
            "examples": [
              "2026-02-02"
            ]
          },
          "end_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "The project's last day, when one is set.",
            "examples": [
              "2026-12-18"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the project was created.",
            "examples": [
              "2026-01-20T09:14:02.381104+00:00"
            ]
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the project last changed. `updated_since` compares with this.",
            "examples": [
              "2026-10-13T14:22:07.512930+00:00"
            ]
          }
        }
      },
      "ProjectList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Project"
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Pass this as cursor to read the next page. Null when there is no next page."
          }
        }
      },
      "Client": {
        "type": "object",
        "description": "Your clients and how they are invoiced. Clients have no `updated_at`, so read the whole list each time.",
        "required": [
          "id",
          "name",
          "org_number",
          "contact_name",
          "contact_email",
          "address",
          "city",
          "zip_code",
          "country",
          "payment_terms",
          "currency",
          "invoice_email",
          "vat_treatment",
          "vat_number",
          "is_active",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The client's id.",
            "examples": [
              "a3e91f04-6c2b-4f55-8d0e-7b19c4d2e6a8"
            ]
          },
          "name": {
            "type": "string",
            "description": "The client's name.",
            "examples": [
              "Nordvik Energi AB"
            ]
          },
          "org_number": {
            "type": [
              "string",
              "null"
            ],
            "description": "The client's organisation number.",
            "examples": [
              "556677-8899"
            ]
          },
          "contact_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "The contact person.",
            "examples": [
              "Karin Lund"
            ]
          },
          "contact_email": {
            "type": [
              "string",
              "null"
            ],
            "description": "The contact person's email address.",
            "examples": [
              "karin.lund@nordvik.example"
            ]
          },
          "address": {
            "type": [
              "string",
              "null"
            ],
            "description": "Street address.",
            "examples": [
              "Hamngatan 12"
            ]
          },
          "city": {
            "type": [
              "string",
              "null"
            ],
            "description": "City.",
            "examples": [
              "Stockholm"
            ]
          },
          "zip_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Postal code.",
            "examples": [
              "111 47"
            ]
          },
          "country": {
            "type": "string",
            "description": "Country code, such as SE.",
            "examples": [
              "SE"
            ]
          },
          "payment_terms": {
            "type": "number",
            "description": "Days until an invoice to this client is due.",
            "examples": [
              30
            ]
          },
          "currency": {
            "type": "string",
            "enum": [
              "SEK",
              "EUR",
              "USD",
              "GBP",
              "NOK",
              "DKK",
              "BAM",
              "CHF",
              "PLN",
              "CZK"
            ],
            "description": "The currency the client is invoiced in.",
            "examples": [
              "SEK"
            ]
          },
          "invoice_email": {
            "type": [
              "string",
              "null"
            ],
            "description": "Where invoices to the client are emailed.",
            "examples": [
              "invoices@nordvik.example"
            ]
          },
          "vat_treatment": {
            "type": "string",
            "enum": [
              "domestic",
              "eu_reverse_charge",
              "outside_eu"
            ],
            "description": "How VAT applies to the client: Swedish VAT, EU reverse charge, or a buyer outside the EU.",
            "examples": [
              "domestic"
            ]
          },
          "vat_number": {
            "type": [
              "string",
              "null"
            ],
            "description": "The client's VAT number.",
            "examples": [
              "SE556677889901"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "False once the client has been deactivated.",
            "examples": [
              true
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the client was created.",
            "examples": [
              "2025-11-04T13:40:51.006217+00:00"
            ]
          }
        }
      },
      "ClientList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Client"
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Pass this as cursor to read the next page. Null when there is no next page."
          }
        }
      },
      "TimeEntry": {
        "type": "object",
        "description": "Hours reported on your projects, by your team and by subcontractors. Hours appear as soon as they are saved, before the week is submitted or approved.",
        "required": [
          "id",
          "timesheet_id",
          "user_id",
          "project_id",
          "vendor_id",
          "date",
          "hours",
          "billable",
          "description",
          "task",
          "invoiced_line_id",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The entry's id.",
            "examples": [
              "e41a7c92-3b5d-4f08-96c1-8a2d4e6f0b73"
            ]
          },
          "timesheet_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "The weekly timesheet the hours belong to. Null for hours bought from a subcontractor.",
            "examples": [
              "c7d2e5b1-9f34-4a60-b8e2-1d5f7a3c9e04"
            ]
          },
          "user_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "The person who reported the hours. Null for hours bought from a subcontractor.",
            "examples": [
              "2b8f6d13-0e7a-4c95-a1d4-6f3e9b2c8a57"
            ]
          },
          "project_id": {
            "type": "string",
            "format": "uuid",
            "description": "The project, an id from `projects`.",
            "examples": [
              "5f0c2a9e-41d7-4b8e-9a51-0d6c3e2f7b10"
            ]
          },
          "vendor_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "The subcontractor the hours were bought from. Null for your own team.",
            "examples": [
              null
            ]
          },
          "date": {
            "type": "string",
            "format": "date",
            "description": "The day the hours were worked.",
            "examples": [
              "2026-10-12"
            ]
          },
          "hours": {
            "type": "number",
            "description": "Hours as a decimal: 7.5 is seven and a half hours.",
            "examples": [
              7.5
            ]
          },
          "billable": {
            "type": "boolean",
            "description": "Whether the hours are billed to the client.",
            "examples": [
              true
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "What was done.",
            "examples": [
              "Pipeline tests for the meter feed"
            ]
          },
          "task": {
            "type": [
              "string",
              "null"
            ],
            "description": "The task the hours were reported on, when one was chosen.",
            "examples": [
              "Development"
            ]
          },
          "invoiced_line_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "The customer invoice line that billed these hours. Null until they are invoiced.",
            "examples": [
              null
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the entry was created.",
            "examples": [
              "2026-10-12T16:05:33.719402+00:00"
            ]
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the entry last changed. `updated_since` compares with this.",
            "examples": [
              "2026-10-12T16:05:33.719402+00:00"
            ]
          }
        }
      },
      "TimeEntryList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TimeEntry"
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Pass this as cursor to read the next page. Null when there is no next page."
          }
        }
      },
      "CustomerInvoice": {
        "type": "object",
        "description": "Invoices and credit notes to your clients. `total_amount` includes VAT.",
        "required": [
          "id",
          "client_id",
          "invoice_number",
          "status",
          "invoice_date",
          "due_date",
          "total_amount",
          "vat_amount",
          "currency",
          "exchange_rate",
          "payment_terms",
          "sent_at",
          "paid_at",
          "credited_invoice_id",
          "vat_treatment",
          "delivery_status",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The invoice's id.",
            "examples": [
              "9d3b1f68-27c4-4e9a-b05d-3c8e1a7f6d42"
            ]
          },
          "client_id": {
            "type": "string",
            "format": "uuid",
            "description": "The client invoiced, an id from clients.",
            "examples": [
              "a3e91f04-6c2b-4f55-8d0e-7b19c4d2e6a8"
            ]
          },
          "invoice_number": {
            "type": "string",
            "description": "The invoice number.",
            "examples": [
              "INV-2026-0142"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "review",
              "sent",
              "overdue",
              "paid",
              "credited",
              "voided"
            ],
            "description": "Where the invoice is. An unpaid invoice past its due date usually still reads `sent`, so compare `due_date` with today to find overdue invoices.",
            "examples": [
              "sent"
            ]
          },
          "invoice_date": {
            "type": "string",
            "format": "date",
            "description": "The invoice date.",
            "examples": [
              "2026-10-01"
            ]
          },
          "due_date": {
            "type": "string",
            "format": "date",
            "description": "The day payment is due.",
            "examples": [
              "2026-10-31"
            ]
          },
          "total_amount": {
            "type": "number",
            "description": "The total including VAT, in the invoice's currency. Negative on a credit note.",
            "examples": [
              156250
            ]
          },
          "vat_amount": {
            "type": "number",
            "description": "The VAT included in `total_amount`.",
            "examples": [
              31250
            ]
          },
          "currency": {
            "type": "string",
            "enum": [
              "SEK",
              "EUR",
              "USD",
              "GBP",
              "NOK",
              "DKK",
              "BAM",
              "CHF",
              "PLN",
              "CZK"
            ],
            "description": "The invoice's currency.",
            "examples": [
              "SEK"
            ]
          },
          "exchange_rate": {
            "type": "number",
            "description": "Multiply an amount by this to get it in your company's base currency. 1 when the invoice is in the base currency.",
            "examples": [
              1
            ]
          },
          "payment_terms": {
            "type": "number",
            "description": "Days from the invoice date to the due date.",
            "examples": [
              30
            ]
          },
          "sent_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the invoice was issued and booked. Whether the email or e-invoice reached the client is in `delivery_status`.",
            "examples": [
              "2026-10-01T08:02:11.204918+00:00"
            ]
          },
          "paid_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the invoice was recorded as paid.",
            "examples": [
              null
            ]
          },
          "credited_invoice_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "On a credit note, the invoice it credits.",
            "examples": [
              null
            ]
          },
          "vat_treatment": {
            "type": "string",
            "enum": [
              "domestic",
              "eu_reverse_charge",
              "outside_eu"
            ],
            "description": "How VAT was applied, fixed when the invoice was issued.",
            "examples": [
              "domestic"
            ]
          },
          "delivery_status": {
            "type": "string",
            "enum": [
              "unsent",
              "queued",
              "sending",
              "delivered",
              "pending_provider",
              "failed"
            ],
            "description": "Where the email or e-invoice delivery is.",
            "examples": [
              "delivered"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the invoice was created.",
            "examples": [
              "2026-09-30T15:48:20.118352+00:00"
            ]
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the invoice last changed. `updated_since` compares with this.",
            "examples": [
              "2026-10-01T08:02:11.204918+00:00"
            ]
          }
        }
      },
      "CustomerInvoiceList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerInvoice"
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Pass this as cursor to read the next page. Null when there is no next page."
          }
        }
      },
      "ExpenseReport": {
        "type": "object",
        "description": "Expense reports with their lines. Amounts include VAT.",
        "required": [
          "id",
          "user_id",
          "title",
          "status",
          "total_amount",
          "currency",
          "submitted_at",
          "approved_at",
          "paid_at",
          "created_at",
          "updated_at",
          "lines"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The report's id.",
            "examples": [
              "0a6e4c2f-8b1d-4f39-a7e5-2c9d1b3f6e84"
            ]
          },
          "user_id": {
            "type": "string",
            "format": "uuid",
            "description": "The person the report belongs to.",
            "examples": [
              "2b8f6d13-0e7a-4c95-a1d4-6f3e9b2c8a57"
            ]
          },
          "title": {
            "type": "string",
            "description": "The report's title.",
            "examples": [
              "Client workshop in Gothenburg"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "submitted",
              "approved",
              "rejected",
              "paid"
            ],
            "description": "Where the report is. `paid` means the money has been paid out.",
            "examples": [
              "approved"
            ]
          },
          "total_amount": {
            "type": "number",
            "description": "The sum of the lines' `amount`, including VAT, added without converting between currencies. For a report with lines in more than one currency, total the lines by their own `currency` instead.",
            "examples": [
              1840
            ]
          },
          "currency": {
            "type": "string",
            "enum": [
              "SEK",
              "EUR",
              "USD",
              "GBP",
              "NOK",
              "DKK",
              "BAM",
              "CHF",
              "PLN",
              "CZK"
            ],
            "description": "The currency set on the report. Each line has its own `currency`, which can differ.",
            "examples": [
              "SEK"
            ]
          },
          "submitted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the report was submitted for approval.",
            "examples": [
              "2026-10-09T07:31:45.660128+00:00"
            ]
          },
          "approved_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the report was approved.",
            "examples": [
              "2026-10-10T10:12:03.090551+00:00"
            ]
          },
          "paid_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the money was paid out.",
            "examples": [
              null
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the report was created.",
            "examples": [
              "2026-10-08T19:20:14.538770+00:00"
            ]
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the report last changed. `updated_since` compares with this.",
            "examples": [
              "2026-10-10T10:12:03.090551+00:00"
            ]
          },
          "lines": {
            "type": "array",
            "description": "Every line on the report, in id order.",
            "items": {
              "$ref": "#/components/schemas/ExpenseLine"
            }
          }
        }
      },
      "ExpenseLine": {
        "type": "object",
        "description": "One line on an expense report.",
        "required": [
          "id",
          "project_id",
          "expense_type",
          "description",
          "amount",
          "vat_amount",
          "currency",
          "date",
          "is_billable",
          "is_wellness",
          "mileage_km",
          "invoiced_line_id"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The line's id.",
            "examples": [
              "f2c9b7e4-1a6d-4e05-b8c3-7d4a2f9e1b65"
            ]
          },
          "project_id": {
            "type": "string",
            "format": "uuid",
            "description": "The project the cost belongs to.",
            "examples": [
              "5f0c2a9e-41d7-4b8e-9a51-0d6c3e2f7b10"
            ]
          },
          "expense_type": {
            "type": "string",
            "enum": [
              "receipt",
              "mileage",
              "per_diem",
              "credit_card",
              "wellness"
            ],
            "description": "The kind of expense.",
            "examples": [
              "receipt"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the expense was for.",
            "examples": [
              "Train Stockholm to Gothenburg"
            ]
          },
          "amount": {
            "type": "number",
            "description": "The amount including VAT, in the line's currency.",
            "examples": [
              1840
            ]
          },
          "vat_amount": {
            "type": "number",
            "description": "The deductible VAT included in `amount`. Always 0 on mileage and per diem lines.",
            "examples": [
              104.15
            ]
          },
          "currency": {
            "type": "string",
            "enum": [
              "SEK",
              "EUR",
              "USD",
              "GBP",
              "NOK",
              "DKK",
              "BAM",
              "CHF",
              "PLN",
              "CZK"
            ],
            "description": "The line's currency.",
            "examples": [
              "SEK"
            ]
          },
          "date": {
            "type": "string",
            "format": "date",
            "description": "The day of the expense.",
            "examples": [
              "2026-10-08"
            ]
          },
          "is_billable": {
            "type": "boolean",
            "description": "Whether the cost is billed on to the client.",
            "examples": [
              true
            ]
          },
          "is_wellness": {
            "type": "boolean",
            "description": "Whether the line counts against the wellness allowance.",
            "examples": [
              false
            ]
          },
          "mileage_km": {
            "type": [
              "number",
              "null"
            ],
            "description": "Kilometres driven, on a mileage line.",
            "examples": [
              null
            ]
          },
          "invoiced_line_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "The customer invoice line that billed the cost on. Null until it is billed.",
            "examples": [
              null
            ]
          }
        }
      },
      "ExpenseReportList": {
        "type": "object",
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExpenseReport"
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Pass this as cursor to read the next page. Null when there is no next page."
          }
        }
      }
    }
  }
}
