{"openapi":"3.1.0","info":{"title":"Osorik API","version":"1.0.0","description":"JSON over HTTPS for scripts and integrations. Send a team API key or an OAuth access token as a bearer token.\n\nErrors return `{ \"code\", \"message\" }` with a stable `code`.\n\nThe [API guide](https://osorik.dev/docs/api) explains authentication, error codes and discovery."},"externalDocs":{"description":"API guide","url":"https://osorik.dev/docs/api"},"servers":[{"url":"https://api.osorik.dev"}],"components":{"securitySchemes":{"ApiKey":{"type":"http","scheme":"bearer","description":"Team API key starting with `osk_`, or an OAuth access token."},"OAuth2":{"type":"oauth2","description":"OAuth 2.1 authorization code flow with PKCE. Clients can register through dynamic client registration at `/api/auth/oauth2/register`.","flows":{"authorizationCode":{"authorizationUrl":"/api/auth/oauth2/authorize","tokenUrl":"/api/auth/oauth2/token","refreshUrl":"/api/auth/oauth2/token","scopes":{"read":"Read team data: contacts, categories, bank accounts, transactions, invoices, expenses, projects and time.","write":"Create and change team data: contacts, categories, transactions, invoice drafts, expenses, projects and time.","offline_access":"Get a refresh token."}}}}},"schemas":{"Team":{"type":"object","properties":{"id":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"name":{"type":"string","example":"Dex"},"email":{"type":["string","null"]},"taxId":{"type":["string","null"]},"address":{"type":["string","null"]},"zipCode":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"country":{"type":"string","example":"PT"},"timeZone":{"type":"string","example":"Europe/Lisbon"},"website":{"type":["string","null"]},"logoUrl":{"type":["string","null"]},"role":{"type":"string","enum":["member","admin","owner"]}},"required":["id","name","email","taxId","address","zipCode","city","state","country","timeZone","website","logoUrl","role"]},"Error":{"type":"object","properties":{"code":{"type":"string","example":"API_KEY_INVALID"},"message":{"type":"string","example":"The API key is invalid or revoked."}},"required":["code","message"]},"ContactPage":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"nextCursor":{"type":["string","null"]}},"required":["data","nextCursor"]},"Contact":{"type":"object","properties":{"id":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"name":{"type":"string","example":"Acme"},"legalName":{"type":"string","example":"Acme, Lda."},"entityType":{"type":"string","enum":["organization","individual","government","nonprofit","other"]},"industry":{"type":"string","enum":["software_and_cloud","professional_services","financial_services","government","employee_benefits","retail","food_and_hospitality","travel_and_transport","telecommunications","utilities","real_estate","healthcare","education","media_and_entertainment","advertising_and_marketing","manufacturing_and_construction","logistics","insurance","nonprofit","other"]},"isClient":{"type":"boolean"},"isPayee":{"type":"boolean"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"website":{"type":["string","null"]},"address":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"zipCode":{"type":["string","null"]},"country":{"type":["string","null"]},"taxId":{"type":["string","null"]},"note":{"type":["string","null"]},"categoryId":{"type":["string","null"],"minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"Default category for this contact’s transactions."},"bankAccount":{"$ref":"#/components/schemas/ContactBankAccount"},"billing":{"$ref":"#/components/schemas/ContactBilling"},"createdAt":{"type":"string","format":"date-time","description":"ISO 8601 timestamp in UTC.","example":"2026-10-11T09:30:00.000Z"}},"required":["id","name","legalName","entityType","industry","isClient","isPayee","email","phone","website","address","city","state","zipCode","country","taxId","note","categoryId","bankAccount","billing","createdAt"]},"ContactBankAccount":{"type":["object","null"],"properties":{"bankName":{"type":["string","null"]},"country":{"type":"string","example":"PT"},"currency":{"type":["string","null"]},"accountNumber":{"type":"string","example":"PT50000201231234567890154"},"accountNumberType":{"type":"string","enum":["iban","local"]},"bic":{"type":["string","null"]}},"required":["bankName","country","currency","accountNumber","accountNumberType","bic"]},"ContactBilling":{"type":["object","null"],"properties":{"email":{"type":["string","null"]},"bccEmails":{"type":"array","items":{"type":"string"}},"address":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"zipCode":{"type":["string","null"]},"country":{"type":["string","null"]},"defaultCurrency":{"type":["string","null"]},"paymentTermsDays":{"type":["number","null"]},"reference":{"type":["string","null"]},"portalEnabled":{"type":"boolean"}},"required":["email","bccEmails","address","city","state","zipCode","country","defaultCurrency","paymentTermsDays","reference","portalEnabled"],"description":"Billing details; `null` unless the contact is a client."},"CreateContact":{"type":"object","properties":{"legalName":{"type":["string","null"],"description":"Registered name; defaults to `name`."},"email":{"type":["string","null"],"minLength":1},"phone":{"type":["string","null"]},"website":{"type":["string","null"]},"address":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"zipCode":{"type":["string","null"]},"country":{"type":["string","null"]},"taxId":{"type":["string","null"],"maxLength":128},"note":{"type":["string","null"]},"categoryId":{"type":["string","null"],"minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"bankAccount":{"type":["object","null"],"properties":{"bankName":{"type":"string"},"country":{"type":"string","description":"Bank country; defaults to the contact’s country."},"currency":{"type":"string"},"accountNumber":{"type":"string","minLength":1},"accountNumberType":{"type":"string","enum":["iban","local"],"description":"Detected from the number when omitted."},"bic":{"type":"string","pattern":"^[A-Z]{6}[A-Z0-9]{2}(?:[A-Z0-9]{3})?$"}},"required":["accountNumber"]},"billing":{"type":["object","null"],"properties":{"email":{"type":"string","minLength":1},"bccEmails":{"type":"array","items":{"type":"string","minLength":1},"maxItems":20},"address":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"zipCode":{"type":"string"},"country":{"type":"string"},"defaultCurrency":{"type":"string"},"paymentTermsDays":{"type":"integer","minimum":0},"reference":{"type":"string"},"portalEnabled":{"type":"boolean"}},"description":"Billing details, kept only while the contact is a client."},"name":{"type":"string","minLength":1},"entityType":{"type":"string","enum":["organization","individual","government","nonprofit","other"],"default":"organization"},"industry":{"type":"string","enum":["software_and_cloud","professional_services","financial_services","government","employee_benefits","retail","food_and_hospitality","travel_and_transport","telecommunications","utilities","real_estate","healthcare","education","media_and_entertainment","advertising_and_marketing","manufacturing_and_construction","logistics","insurance","nonprofit","other"],"default":"other"},"isClient":{"type":"boolean","default":false},"isPayee":{"type":"boolean","default":false}},"required":["name"]},"UpdateContact":{"type":"object","properties":{"legalName":{"type":["string","null"],"description":"Registered name; defaults to `name`."},"email":{"type":["string","null"],"minLength":1},"phone":{"type":["string","null"]},"website":{"type":["string","null"]},"address":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"zipCode":{"type":["string","null"]},"country":{"type":["string","null"]},"taxId":{"type":["string","null"],"maxLength":128},"note":{"type":["string","null"]},"categoryId":{"type":["string","null"],"minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"bankAccount":{"type":["object","null"],"properties":{"bankName":{"type":"string"},"country":{"type":"string","description":"Bank country; defaults to the contact’s country."},"currency":{"type":"string"},"accountNumber":{"type":"string","minLength":1},"accountNumberType":{"type":"string","enum":["iban","local"],"description":"Detected from the number when omitted."},"bic":{"type":"string","pattern":"^[A-Z]{6}[A-Z0-9]{2}(?:[A-Z0-9]{3})?$"}},"required":["accountNumber"]},"billing":{"type":["object","null"],"properties":{"email":{"type":"string","minLength":1},"bccEmails":{"type":"array","items":{"type":"string","minLength":1},"maxItems":20},"address":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"zipCode":{"type":"string"},"country":{"type":"string"},"defaultCurrency":{"type":"string"},"paymentTermsDays":{"type":"integer","minimum":0},"reference":{"type":"string"},"portalEnabled":{"type":"boolean"}},"description":"Billing details, kept only while the contact is a client."},"name":{"type":"string","minLength":1},"entityType":{"type":"string","enum":["organization","individual","government","nonprofit","other"]},"industry":{"type":"string","enum":["software_and_cloud","professional_services","financial_services","government","employee_benefits","retail","food_and_hospitality","travel_and_transport","telecommunications","utilities","real_estate","healthcare","education","media_and_entertainment","advertising_and_marketing","manufacturing_and_construction","logistics","insurance","nonprofit","other"]},"isClient":{"type":"boolean"},"isPayee":{"type":"boolean"}}},"CategoryPage":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Category"}},"nextCursor":{"type":["string","null"]}},"required":["data","nextCursor"]},"Category":{"type":"object","properties":{"id":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"name":{"type":"string","example":"Software subscriptions"},"description":{"type":["string","null"]},"type":{"type":"string","enum":["income","expense","asset","tax","financing","owner","transfer","other"]},"accountingCode":{"type":["string","null"],"description":"Code in the accountant’s chart of accounts.","example":"6226"},"archived":{"type":"boolean"},"systemRole":{"type":["string","null"],"enum":["internal_transfer",null],"description":"Workflow role of a required category, such as `internal_transfer`; `null` for ordinary categories."}},"required":["id","name","description","type","accountingCode","archived","systemRole"]},"CreateCategory":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"description":{"type":"string","minLength":1,"maxLength":240},"type":{"type":"string","enum":["income","expense","asset","tax","financing","owner","transfer","other"]},"accountingCode":{"type":"string","maxLength":32}},"required":["name","description","type"]},"BankAccountPage":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BankAccount"}},"nextCursor":{"type":["string","null"]}},"required":["data","nextCursor"]},"BankAccount":{"type":"object","properties":{"id":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"displayName":{"type":["string","null"],"description":"Name the team gave the account.","example":"Main account"},"accountHolderName":{"type":["string","null"]},"bankName":{"type":["string","null"],"example":"Millennium BCP"},"accountType":{"type":["string","null"],"enum":["current","savings","business","personal","card","cash","loan","overdraft","money_market","prepaid","settlement","salary","tax","investment","other",null]},"accountNumber":{"type":["string","null"],"example":"PT50000201231234567890154"},"accountNumberType":{"$ref":"#/components/schemas/BankAccountNumberType"},"bic":{"type":["string","null"]},"currency":{"type":["string","null"],"example":"EUR"},"balance":{"type":["string","null"],"description":"Last balance the bank reported, in `currency`; `null` when unknown.","example":"1250.00"}},"required":["id","displayName","accountHolderName","bankName","accountType","accountNumber","accountNumberType","bic","currency","balance"]},"BankAccountNumberType":{"type":["string","null"],"enum":["iban","bban","sort-code-account-number","us-routing-account-number","pan","masked-pan","msisdn","other",null]},"TransactionPage":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Transaction"}},"nextCursor":{"type":["string","null"]}},"required":["data","nextCursor"]},"Transaction":{"type":"object","properties":{"id":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"date":{"type":"string","description":"Date as `YYYY-MM-DD`.","example":"2026-10-11"},"direction":{"$ref":"#/components/schemas/TransactionDirection"},"amount":{"type":"string","description":"Absolute amount in the account currency; see `direction`.","example":"1250.00"},"currency":{"type":"string","example":"EUR"},"instructedAmount":{"type":["string","null"],"description":"Original amount when the payment was made in another currency.","example":"1250.00"},"instructedCurrency":{"type":["string","null"]},"title":{"type":["string","null"],"example":"Acme"},"subtitle":{"type":["string","null"]},"bankAccountId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"categoryId":{"type":["string","null"],"minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"contactId":{"type":["string","null"],"minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"contactName":{"type":["string","null"]},"projectId":{"type":["string","null"],"minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"note":{"type":["string","null"]},"status":{"$ref":"#/components/schemas/TransactionStatus"},"reconciliationStatus":{"type":["string","null"],"enum":["unmatched","partial","matched","difference_accepted","review",null],"description":"How much of the transaction is matched to expenses or invoices."},"internal":{"type":"boolean","description":"A transfer between the team’s own accounts."},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time","description":"ISO 8601 timestamp in UTC.","example":"2026-10-11T09:30:00.000Z"}},"required":["id","date","direction","amount","currency","instructedAmount","instructedCurrency","title","subtitle","bankAccountId","categoryId","contactId","contactName","projectId","note","status","reconciliationStatus","internal","archived","createdAt"]},"TransactionDirection":{"type":"string","enum":["credit","debit","unknown"]},"TransactionStatus":{"type":"string","enum":["uncategorized","in_progress","complete","needs_review","no_impact"]},"UpdateTransaction":{"type":"object","properties":{"categoryId":{"type":["string","null"],"minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"An active category; `null` clears it."},"note":{"type":["string","null"],"maxLength":500,"description":"Up to 500 characters; `null` or blank clears it."},"contactId":{"type":["string","null"],"minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"The counterparty contact; `null` clears it."},"projectId":{"type":["string","null"],"minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"An open project; `null` clears it. Needs the owner or admin role."},"archived":{"type":"boolean"}}},"InvoicePage":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Invoice"}},"nextCursor":{"type":["string","null"]}},"required":["data","nextCursor"]},"Invoice":{"type":"object","properties":{"id":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"number":{"type":["string","null"],"description":"Invoice number, assigned when it is issued; `null` for drafts.","example":"INV-2026-0001"},"title":{"type":"string","example":"Design services"},"status":{"type":"string","enum":["draft","issuing","issue_failed","issued","void"],"description":"Lifecycle state: `draft`, `issuing`, `issue_failed`, `issued` or `void`. Only drafts can be changed or deleted."},"deliveryStatus":{"type":"string","enum":["not_sent","queued","sent","failed"],"description":"Email delivery state of the issued invoice."},"paymentStatus":{"type":"string","enum":["unmatched","partial","matched","difference_accepted","review"],"description":"How far bank payments cover the total."},"clientId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"Contact the invoice bills."},"clientName":{"type":"string","description":"Client name, frozen when the invoice is issued.","example":"Acme"},"categoryId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"Income category."},"bankAccountId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"Bank account the client pays into."},"currency":{"type":"string","example":"EUR"},"issueDate":{"type":"string","description":"Date as `YYYY-MM-DD`.","example":"2026-10-11"},"dueDate":{"type":"string","description":"Date as `YYYY-MM-DD`.","example":"2026-10-11"},"discountPercentage":{"type":["number","null"],"description":"Discount on the line subtotal, from 0 to 100.","example":10},"discountAmount":{"type":["string","null"],"description":"Discount in the invoice currency; `null` without one.","example":"1250.00"},"totalAmount":{"type":"string","description":"Total after discount, in the invoice currency.","example":"1250.00"},"paidAmount":{"type":"string","description":"Amount matched to bank payments so far.","example":"1250.00"},"note":{"type":["string","null"],"description":"Note printed on the invoice for the client."},"issuedAt":{"type":["string","null"],"format":"date-time","description":"ISO 8601 timestamp in UTC.","example":"2026-10-11T09:30:00.000Z"},"voidedAt":{"type":["string","null"],"format":"date-time","description":"ISO 8601 timestamp in UTC.","example":"2026-10-11T09:30:00.000Z"},"createdAt":{"type":"string","format":"date-time","description":"ISO 8601 timestamp in UTC.","example":"2026-10-11T09:30:00.000Z"},"updatedAt":{"type":"string","format":"date-time","description":"ISO 8601 timestamp in UTC.","example":"2026-10-11T09:30:00.000Z"}},"required":["id","number","title","status","deliveryStatus","paymentStatus","clientId","clientName","categoryId","bankAccountId","currency","issueDate","dueDate","discountPercentage","discountAmount","totalAmount","paidAmount","note","issuedAt","voidedAt","createdAt","updatedAt"]},"InvoiceDetail":{"allOf":[{"$ref":"#/components/schemas/Invoice"},{"type":"object","properties":{"lines":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceLine"}},"pdfUrl":{"type":["string","null"],"description":"Temporary download URL of the issued PDF; `null` until it is rendered."}},"required":["lines","pdfUrl"]}]},"InvoiceLine":{"type":"object","properties":{"description":{"type":"string","example":"Product design"},"quantity":{"type":"string","description":"Decimal quantity with up to 6 decimals.","example":"2.5"},"unitPrice":{"type":"string","description":"Decimal unit price with up to 6 decimals.","example":"80"},"lineTotal":{"type":"string","description":"Quantity times unit price, rounded to the currency.","example":"1250.00"}},"required":["description","quantity","unitPrice","lineTotal"]},"CreateInvoiceDraft":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":120},"clientId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"A contact that is a client."},"lines":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceLineInput"},"minItems":1,"maxItems":200},"issueDate":{"type":"string","format":"date"},"categoryId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"Active income category; defaults to the invoice settings’ category."},"bankAccountId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"Bank account with payment instructions; defaults to the invoice settings’ account, then the first such account."},"currency":{"type":"string","description":"Defaults to the client’s currency, then the bank account’s currency, then the team currency."},"dueDate":{"type":"string","format":"date","description":"On or after `issueDate`; defaults to `issueDate` plus the client’s payment terms, then the invoice settings’ terms."},"discountPercentage":{"type":"number","minimum":0,"maximum":100},"note":{"type":"string","maxLength":2000,"description":"Defaults to the invoice settings’ note."}},"required":["title","clientId","lines","issueDate"]},"InvoiceLineInput":{"type":"object","properties":{"description":{"type":"string","minLength":1,"maxLength":500},"quantity":{"type":"string","pattern":"^\\d+(\\.\\d{1,6})?$"},"unitPrice":{"type":"string","pattern":"^\\d+(\\.\\d{1,6})?$"}},"required":["description","quantity","unitPrice"]},"UpdateInvoiceDraft":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":120},"clientId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"lines":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceLineInput"},"minItems":1,"maxItems":200,"description":"Replaces every line of the draft."},"issueDate":{"type":"string","format":"date"},"dueDate":{"type":"string","format":"date"},"categoryId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"bankAccountId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"currency":{"type":"string"},"discountPercentage":{"type":["number","null"],"minimum":0,"maximum":100},"note":{"type":["string","null"],"maxLength":2000}}},"Deleted":{"type":"object","properties":{"id":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"deleted":{"type":"boolean","enum":[true]}},"required":["id","deleted"]},"InvoiceSettings":{"type":"object","properties":{"prefix":{"type":"string","description":"Prefix of invoice numbers, such as `INV` in `INV-2026-0001`.","example":"INV"},"defaultPaymentTermsDays":{"type":"number","description":"Days from issue date to due date for new invoices.","example":30},"defaultCategoryId":{"type":["string","null"],"minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"defaultBankAccountId":{"type":["string","null"],"minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"defaultNote":{"type":["string","null"]}},"required":["prefix","defaultPaymentTermsDays","defaultCategoryId","defaultBankAccountId","defaultNote"]},"ExpensePage":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Expense"}},"nextCursor":{"type":["string","null"]}},"required":["data","nextCursor"]},"Expense":{"type":"object","properties":{"id":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"status":{"type":"string","enum":["processing","failed","unmatched","partial","matched","difference_accepted"],"description":"`processing` while the document is read, `failed` when that failed, then how much of it is matched to transactions."},"payeeId":{"type":["string","null"],"minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"payeeName":{"type":["string","null"]},"reference":{"type":["string","null"],"example":"INV-2026-0042"},"date":{"type":["string","null"],"description":"Date as `YYYY-MM-DD`.","example":"2026-10-11"},"dueDate":{"type":["string","null"],"description":"Date as `YYYY-MM-DD`.","example":"2026-10-11"},"currency":{"type":["string","null"],"example":"EUR"},"amount":{"type":["string","null"],"description":"Total including tax, in `currency`.","example":"1250.00"},"taxType":{"type":["string","null"],"enum":["vat","sales_tax","gst","withholding_tax","service_tax","excise_tax","reverse_charge","custom_tax",null]},"taxAmount":{"type":["string","null"],"description":"Decimal amount in major units, such as `1250.00`.","example":"1250.00"},"reconciledAmount":{"type":"string","description":"Part of `amount` matched to bank transactions.","example":"1250.00"},"archived":{"type":"boolean"},"documentId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"extractionError":{"type":["string","null"],"description":"Why reading the document failed, when `status` is `failed`."},"createdAt":{"type":"string","format":"date-time","description":"ISO 8601 timestamp in UTC.","example":"2026-10-11T09:30:00.000Z"}},"required":["id","status","payeeId","payeeName","reference","date","dueDate","currency","amount","taxType","taxAmount","reconciledAmount","archived","documentId","extractionError","createdAt"]},"ExpenseDetail":{"allOf":[{"$ref":"#/components/schemas/Expense"},{"type":"object","properties":{"documentUrl":{"type":["string","null"],"description":"Short-lived link to the expense document."}},"required":["documentUrl"]}]},"UpdateExpense":{"type":"object","properties":{"payeeId":{"type":["string","null"],"minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"A contact marked as a payee; `null` clears it."},"reference":{"type":["string","null"]},"date":{"type":["string","null"],"format":"date","description":"`YYYY-MM-DD`."},"dueDate":{"type":["string","null"],"format":"date","description":"`YYYY-MM-DD`, on or after `date`."},"currency":{"type":"string"},"amount":{"type":"string","maxLength":32,"pattern":"^(?:0|[1-9]\\d*)(?:\\.\\d+)?$"},"taxType":{"type":["string","null"],"enum":["vat","sales_tax","gst","withholding_tax","service_tax","excise_tax","reverse_charge","custom_tax",null]},"taxAmount":{"type":["string","null"],"maxLength":32,"pattern":"^(?:0|[1-9]\\d*)(?:\\.\\d+)?$","example":"233.74"},"archived":{"type":"boolean"}}},"ProjectPage":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Project"}},"nextCursor":{"type":["string","null"]}},"required":["data","nextCursor"]},"Project":{"type":"object","properties":{"id":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"name":{"type":"string","example":"Website redesign"},"description":{"type":["string","null"]},"status":{"type":"string","enum":["planned","active","on_hold","completed","cancelled"]},"clientId":{"type":["string","null"],"minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"Client contact of the project; `null` for internal work."},"currency":{"type":"string","example":"EUR"},"startDate":{"type":["string","null"],"description":"Date as `YYYY-MM-DD`.","example":"2026-10-11"},"targetEndDate":{"type":["string","null"],"description":"Date as `YYYY-MM-DD`.","example":"2026-10-11"},"timeRoundingMinutes":{"anyOf":[{"type":"number","enum":[0]},{"type":"number","enum":[5]},{"type":"number","enum":[10]},{"type":"number","enum":[15]},{"type":"number","enum":[30]},{"type":"null"}],"description":"Minutes completed billable time entries round to: 0 (exact), 5, 10, 15 or 30."},"closedAt":{"type":["string","null"],"format":"date-time","description":"When the project was completed or cancelled.","example":"2026-10-11T09:30:00.000Z"},"createdAt":{"type":"string","format":"date-time","description":"ISO 8601 timestamp in UTC.","example":"2026-10-11T09:30:00.000Z"},"updatedAt":{"type":"string","format":"date-time","description":"ISO 8601 timestamp in UTC.","example":"2026-10-11T09:30:00.000Z"}},"required":["id","name","description","status","clientId","currency","startDate","targetEndDate","timeRoundingMinutes","closedAt","createdAt","updatedAt"]},"ProjectDetail":{"allOf":[{"$ref":"#/components/schemas/Project"},{"type":"object","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ProjectMember"}}},"required":["members"]}]},"ProjectMember":{"type":"object","properties":{"userId":{"type":"string"},"name":{"type":["string","null"]},"billableRate":{"type":["string","null"],"description":"Hourly rate in the project currency; `null` unless you are a team owner or admin.","example":"1250.00"}},"required":["userId","name","billableRate"]},"CreateProject":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":"string","maxLength":2000},"clientId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"Client contact to bill; omit for internal work."},"currency":{"type":"string"},"startDate":{"type":"string","format":"date"},"targetEndDate":{"type":"string","format":"date","description":"Planned end date, on or after `startDate`."},"timeRoundingMinutes":{"anyOf":[{"type":"number","enum":[0]},{"type":"number","enum":[5]},{"type":"number","enum":[10]},{"type":"number","enum":[15]},{"type":"number","enum":[30]}],"default":15,"description":"Minutes completed billable time entries round to: 0 (exact), 5, 10, 15 or 30."},"billableRate":{"type":"string","pattern":"^(?:0|[1-9]\\d*)(?:\\.\\d+)?$","description":"Your own hourly rate on the project, a decimal string in its currency such as `85.00`; `0` when the work is not charged."}},"required":["name","currency","billableRate"]},"UpdateProject":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":["string","null"],"maxLength":2000},"clientId":{"type":["string","null"],"minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"currency":{"type":"string"},"startDate":{"type":["string","null"],"format":"date"},"targetEndDate":{"type":["string","null"],"format":"date"},"timeRoundingMinutes":{"anyOf":[{"type":"number","enum":[0]},{"type":"number","enum":[5]},{"type":"number","enum":[10]},{"type":"number","enum":[15]},{"type":"number","enum":[30]}],"description":"Minutes completed billable time entries round to: 0 (exact), 5, 10, 15 or 30."},"status":{"type":"string","enum":["planned","active","on_hold","completed","cancelled"],"description":"`completed` and `cancelled` close the project; other states reopen it."}}},"TimeTaskPage":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TimeTask"}},"nextCursor":{"type":["string","null"]}},"required":["data","nextCursor"]},"TimeTask":{"type":"object","properties":{"id":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"projectId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"name":{"type":"string","example":"Design"},"description":{"type":["string","null"]},"archived":{"type":"boolean","description":"Archived tasks keep their history but take no new time."}},"required":["id","projectId","name","description","archived"]},"CreateTimeTask":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":"string","maxLength":500}},"required":["name"]},"TimeEntryList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TimeEntry"}},"truncated":{"type":"boolean","description":"More than 1000 entries matched; narrow the range or add filters."}},"required":["data","truncated"]},"TimeEntry":{"type":"object","properties":{"id":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"projectId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"projectName":{"type":["string","null"]},"taskId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"taskName":{"type":["string","null"]},"clientId":{"type":["string","null"],"minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"Client of the project; `null` for internal projects."},"clientName":{"type":["string","null"]},"member":{"type":"object","properties":{"id":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"name":{"type":["string","null"]}},"required":["id","name"],"description":"Team member the time belongs to."},"status":{"type":"string","enum":["running","completed"]},"startAt":{"type":"string","format":"date-time","description":"ISO 8601 timestamp in UTC.","example":"2026-10-11T09:30:00.000Z"},"endAt":{"type":["string","null"],"format":"date-time","description":"`null` while the timer is running.","example":"2026-10-11T09:30:00.000Z"},"actualMinutes":{"type":["integer","null"],"description":"Tracked minutes; `null` while running."},"billableMinutes":{"type":["integer","null"],"description":"Minutes after the project’s rounding increment; `null` while running."},"billable":{"type":"boolean"},"billableRate":{"type":["string","null"],"description":"Hourly rate snapshotted when the time was recorded; `null` for non-billable time and for callers who are not owners or admins.","example":"1250.00"},"currency":{"type":"string","example":"EUR"}},"required":["id","projectId","projectName","taskId","taskName","clientId","clientName","member","status","startAt","endAt","actualMinutes","billableMinutes","billable","billableRate","currency"]},"CreateTimeEntry":{"type":"object","properties":{"projectId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"taskId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"startAt":{"type":"string","format":"date-time","example":"2026-10-11T09:30:00Z"},"endAt":{"type":"string","format":"date-time","example":"2026-10-11T09:30:00Z"},"billable":{"type":"boolean"}},"required":["projectId","taskId","startAt","endAt","billable"]},"UpdateTimeEntry":{"type":"object","properties":{"projectId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"taskId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"startAt":{"type":"string","format":"date-time","example":"2026-10-11T09:30:00Z"},"endAt":{"type":"string","format":"date-time","example":"2026-10-11T09:30:00Z"},"billable":{"type":"boolean"},"memberId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"Moves the entry to another member assigned to the project. Owners and admins only."}}},"Timer":{"type":"object","properties":{"entry":{"allOf":[{"$ref":"#/components/schemas/TimeEntry"},{"type":["object","null"],"description":"The running entry, or `null` when no timer is running."}]}},"required":["entry"]},"StartTimer":{"type":"object","properties":{"projectId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"taskId":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"billable":{"type":"boolean"}},"required":["projectId","taskId","billable"]}},"parameters":{}},"paths":{"/v1/team":{"get":{"operationId":"getTeam","summary":"Get the team","description":"Returns the Osorik team (workspace) this connection acts in: name, contact and tax details, address, country, time zone, logo URL and the caller's role.","tags":["Team"],"security":[{"ApiKey":[]},{"OAuth2":["read"]}],"responses":{"200":{"description":"Get the team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Team"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `read` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/contacts":{"get":{"operationId":"listContacts","summary":"List contacts","description":"Lists the team’s contacts, the people and organizations it pays (payees) or bills (clients), sorted by name or by relevance when `search` is set. Filter by `role` to get only clients or payees.","tags":["Contacts"],"security":[{"ApiKey":[]},{"OAuth2":["read"]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"Most items to return, 1 to 100."},"required":false,"description":"Most items to return, 1 to 100.","name":"limit","in":"query"},{"schema":{"type":"string","description":"`nextCursor` from the previous page."},"required":false,"description":"`nextCursor` from the previous page.","name":"cursor","in":"query"},{"schema":{"type":"string","description":"Full-text search over names, emails and tax IDs."},"required":false,"description":"Full-text search over names, emails and tax IDs.","name":"search","in":"query"},{"schema":{"type":"string","enum":["client","payee"],"description":"Only clients or only payees."},"required":false,"description":"Only clients or only payees.","name":"role","in":"query"}],"responses":{"200":{"description":"List contacts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactPage"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `read` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createContact","summary":"Create a contact","description":"Creates a contact. When the team already has a contact with the same tax ID and country, email or legal name, that contact is returned instead of a duplicate. Set `isClient` to bill the contact and `isPayee` to record payments to it.","tags":["Contacts"],"security":[{"ApiKey":[]},{"OAuth2":["write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateContact"}}}},"responses":{"201":{"description":"Create a contact","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `write` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The record is in a state that blocks this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/contacts/{contactId}":{"get":{"operationId":"getContact","summary":"Get a contact","description":"Returns one contact with its bank account and, for clients, its billing details.","tags":["Contacts"],"security":[{"ApiKey":[]},{"OAuth2":["read"]}],"parameters":[{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":true,"name":"contactId","in":"path"}],"responses":{"200":{"description":"Get a contact","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `read` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateContact","summary":"Update a contact","description":"Changes the fields sent and keeps the rest; `null` clears an optional field. `bankAccount` and `billing` replace the whole object.","tags":["Contacts"],"security":[{"ApiKey":[]},{"OAuth2":["write"]}],"parameters":[{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":true,"name":"contactId","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateContact"}}}},"responses":{"200":{"description":"Update a contact","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `write` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The record is in a state that blocks this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/categories":{"get":{"operationId":"listCategories","summary":"List categories","description":"Lists the team’s accounting categories (income, expense, transfer and the other types), grouped by type and sorted by name. Use a category `id` to classify transactions, contacts and invoices. Archived categories are left out unless `includeArchived` is true. The list holds at most 100 categories, so `nextCursor` is always `null`.","tags":["Categories"],"security":[{"ApiKey":[]},{"OAuth2":["read"]}],"parameters":[{"schema":{"type":"boolean","default":false,"description":"Also return archived categories."},"required":false,"description":"Also return archived categories.","name":"includeArchived","in":"query"}],"responses":{"200":{"description":"List categories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryPage"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `read` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createCategory","summary":"Create a category","description":"Creates a custom accounting category and returns it. Only team owners and admins can manage categories, and a team can have at most 100. Check `list_categories` first to reuse an existing category.","tags":["Categories"],"security":[{"ApiKey":[]},{"OAuth2":["write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCategory"}}}},"responses":{"201":{"description":"Create a category","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Category"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `write` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The record is in a state that blocks this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/bank-accounts":{"get":{"operationId":"listBankAccounts","summary":"List bank accounts","description":"Lists the team’s bank accounts with their account number, currency and last reported balance. All accounts come back in one page (`nextCursor` is always `null`). Use an account `id` as `bankAccountId` to filter transactions.","tags":["Bank accounts"],"security":[{"ApiKey":[]},{"OAuth2":["read"]}],"responses":{"200":{"description":"List bank accounts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BankAccountPage"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `read` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/transactions":{"get":{"operationId":"listTransactions","summary":"List transactions","description":"Lists the team’s booked bank transactions, newest first. Filter by bank account, category (`uncategorized` for none), project, date range, direction or bookkeeping status, or search titles and counterparties. Archived transactions are left out unless `archived` is `true`. Amounts are absolute decimal strings; `direction` says whether money came in (`credit`) or went out (`debit`). A page can hold fewer items than `limit` before the last one, so keep following `nextCursor` until it is `null`.","tags":["Transactions"],"security":[{"ApiKey":[]},{"OAuth2":["read"]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"Most items to return, 1 to 100."},"required":false,"description":"Most items to return, 1 to 100.","name":"limit","in":"query"},{"schema":{"type":"string","description":"`nextCursor` from the previous page."},"required":false,"description":"`nextCursor` from the previous page.","name":"cursor","in":"query"},{"schema":{"type":"string","description":"Full-text search over titles, counterparties and notes."},"required":false,"description":"Full-text search over titles, counterparties and notes.","name":"search","in":"query"},{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":false,"name":"bankAccountId","in":"query"},{"schema":{"type":"string","minLength":1,"description":"A category id, or `uncategorized` for transactions without one."},"required":false,"description":"A category id, or `uncategorized` for transactions without one.","name":"categoryId","in":"query"},{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":false,"name":"projectId","in":"query"},{"schema":{"type":"string","format":"date","description":"Earliest booking date, `YYYY-MM-DD`."},"required":false,"description":"Earliest booking date, `YYYY-MM-DD`.","name":"dateFrom","in":"query"},{"schema":{"type":"string","format":"date","description":"Latest booking date, `YYYY-MM-DD`."},"required":false,"description":"Latest booking date, `YYYY-MM-DD`.","name":"dateTo","in":"query"},{"schema":{"type":"string","enum":["credit","debit"]},"required":false,"name":"direction","in":"query"},{"schema":{"$ref":"#/components/schemas/TransactionStatus"},"required":false,"name":"status","in":"query"},{"schema":{"type":"boolean","description":"List archived transactions instead; defaults to `false`."},"required":false,"description":"List archived transactions instead; defaults to `false`.","name":"archived","in":"query"}],"responses":{"200":{"description":"List transactions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionPage"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `read` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/transactions/{transactionId}":{"get":{"operationId":"getTransaction","summary":"Get a transaction","description":"Returns one bank transaction with its category, contact, project, note and bookkeeping status.","tags":["Transactions"],"security":[{"ApiKey":[]},{"OAuth2":["read"]}],"parameters":[{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":true,"name":"transactionId","in":"path"}],"responses":{"200":{"description":"Get a transaction","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Transaction"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `read` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateTransaction","summary":"Classify a transaction","description":"Sets the category, contact, project, note or archive flag of a transaction and keeps the fields not sent; `null` clears one. Bank data such as the amount and date cannot change. A category on one side of a linked transfer applies to both sides, debits cannot take income categories, and transfer categories cannot be combined with a project. Setting or clearing `projectId` needs the owner or admin role, and only open projects accept transactions.","tags":["Transactions"],"security":[{"ApiKey":[]},{"OAuth2":["write"]}],"parameters":[{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":true,"name":"transactionId","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTransaction"}}}},"responses":{"200":{"description":"Classify a transaction","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Transaction"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `write` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The record is in a state that blocks this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/invoices":{"get":{"operationId":"listInvoices","summary":"List invoices","description":"Lists the team’s outgoing invoices, newest first or by relevance when `search` is set, without their lines. Filter by lifecycle `status` (for example `draft` or `issued`) and by `clientId`. Amounts are decimal strings in the invoice currency.","tags":["Invoices"],"security":[{"ApiKey":[]},{"OAuth2":["read"]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"Most items to return, 1 to 100."},"required":false,"description":"Most items to return, 1 to 100.","name":"limit","in":"query"},{"schema":{"type":"string","description":"`nextCursor` from the previous page."},"required":false,"description":"`nextCursor` from the previous page.","name":"cursor","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["draft","issuing","issue_failed","issued","void"]},"description":"Only invoices in these lifecycle states."},"required":false,"description":"Only invoices in these lifecycle states.","name":"status","in":"query"},{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"Only invoices billed to this client."},"required":false,"description":"Only invoices billed to this client.","name":"clientId","in":"query"},{"schema":{"type":"string","description":"Full-text search over titles, client names and numbers."},"required":false,"description":"Full-text search over titles, client names and numbers.","name":"search","in":"query"}],"responses":{"200":{"description":"List invoices","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoicePage"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `read` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createInvoiceDraft","summary":"Create an invoice draft","description":"Creates an unnumbered invoice draft for a client contact and returns it with its lines and totals. Fields left out are filled from the client’s billing defaults and the team’s invoice settings (see `get_invoice_settings`): currency, due date (issue date plus payment terms), category, bank account and note. The category must be an active income category and the bank account one with payment instructions. Drafts are not sent or numbered; issue them in Osorik.","tags":["Invoices"],"security":[{"ApiKey":[]},{"OAuth2":["write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInvoiceDraft"}}}},"responses":{"201":{"description":"Create an invoice draft","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceDetail"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `write` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The record is in a state that blocks this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/invoices/{invoiceId}":{"get":{"operationId":"getInvoice","summary":"Get an invoice","description":"Returns one invoice with its lines and, once it is issued and rendered, a temporary `pdfUrl` to download its PDF.","tags":["Invoices"],"security":[{"ApiKey":[]},{"OAuth2":["read"]}],"parameters":[{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":true,"name":"invoiceId","in":"path"}],"responses":{"200":{"description":"Get an invoice","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceDetail"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `read` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateInvoiceDraft","summary":"Update an invoice draft","description":"Changes the fields sent on a draft and keeps the rest; `null` clears the discount or note, and `lines` replaces every line. Totals are recalculated. Invoices that are no longer drafts cannot be changed (409).","tags":["Invoices"],"security":[{"ApiKey":[]},{"OAuth2":["write"]}],"parameters":[{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":true,"name":"invoiceId","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateInvoiceDraft"}}}},"responses":{"200":{"description":"Update an invoice draft","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceDetail"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `write` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The record is in a state that blocks this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteInvoiceDraft","summary":"Delete an invoice draft","description":"Permanently deletes a draft that was never numbered, with its lines. Issued, voided and numbered invoices cannot be deleted (409).","tags":["Invoices"],"security":[{"ApiKey":[]},{"OAuth2":["write"]}],"parameters":[{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":true,"name":"invoiceId","in":"path"}],"responses":{"200":{"description":"Delete an invoice draft","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Deleted"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `write` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The record is in a state that blocks this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/invoice-settings":{"get":{"operationId":"getInvoiceSettings","summary":"Get invoice settings","description":"Returns the team’s invoice number prefix and the defaults new drafts use: currency, payment terms in days, income category, bank account and note. Unset defaults are `null`.","tags":["Invoices"],"security":[{"ApiKey":[]},{"OAuth2":["read"]}],"responses":{"200":{"description":"Get invoice settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceSettings"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `read` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/expenses":{"get":{"operationId":"listExpenses","summary":"List expenses","description":"Lists the team’s expenses, the bills and receipts it uploaded, newest first. Filter by `status` (such as `unmatched` for expenses not yet matched to a bank transaction), by payee, or search payee names and references. Archived expenses are left out unless `archived` is `true`. A page can hold fewer items than `limit` before the last one, so keep following `nextCursor` until it is `null`.","tags":["Expenses"],"security":[{"ApiKey":[]},{"OAuth2":["read"]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"Most items to return, 1 to 100."},"required":false,"description":"Most items to return, 1 to 100.","name":"limit","in":"query"},{"schema":{"type":"string","description":"`nextCursor` from the previous page."},"required":false,"description":"`nextCursor` from the previous page.","name":"cursor","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["processing","failed","unmatched","partial","matched","difference_accepted"]},"description":"Only expenses in these statuses; all when omitted."},"required":false,"description":"Only expenses in these statuses; all when omitted.","name":"status","in":"query"},{"schema":{"type":"boolean","description":"List archived expenses instead; defaults to `false`."},"required":false,"description":"List archived expenses instead; defaults to `false`.","name":"archived","in":"query"},{"schema":{"type":"string","description":"Full-text search over payee names, references and amounts."},"required":false,"description":"Full-text search over payee names, references and amounts.","name":"search","in":"query"},{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"Only expenses of this payee contact."},"required":false,"description":"Only expenses of this payee contact.","name":"payeeId","in":"query"}],"responses":{"200":{"description":"List expenses","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpensePage"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `read` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/expenses/{expenseId}":{"get":{"operationId":"getExpense","summary":"Get an expense","description":"Returns one expense with its extracted details and a short-lived `documentUrl` to download the uploaded document.","tags":["Expenses"],"security":[{"ApiKey":[]},{"OAuth2":["read"]}],"parameters":[{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":true,"name":"expenseId","in":"path"}],"responses":{"200":{"description":"Get an expense","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpenseDetail"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `read` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateExpense","summary":"Update an expense","description":"Changes the fields sent and keeps the rest; `null` clears an optional field. Amounts are decimal strings in `currency`. Details can change only while the expense is `unmatched` (otherwise `EXPENSE_NOT_EDITABLE`); `archived` can change in any status. `payeeId` must be a contact marked as a payee.","tags":["Expenses"],"security":[{"ApiKey":[]},{"OAuth2":["write"]}],"parameters":[{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":true,"name":"expenseId","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateExpense"}}}},"responses":{"200":{"description":"Update an expense","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Expense"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `write` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The record is in a state that blocks this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/projects":{"get":{"operationId":"listProjects","summary":"List projects","description":"Lists the team’s projects, most recently updated first, or by relevance when `search` is set. Filter by `status` or `clientId`.","tags":["Projects"],"security":[{"ApiKey":[]},{"OAuth2":["read"]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"Most items to return, 1 to 100."},"required":false,"description":"Most items to return, 1 to 100.","name":"limit","in":"query"},{"schema":{"type":"string","description":"`nextCursor` from the previous page."},"required":false,"description":"`nextCursor` from the previous page.","name":"cursor","in":"query"},{"schema":{"type":"string","enum":["planned","active","on_hold","completed","cancelled"],"description":"Only projects in this lifecycle state."},"required":false,"description":"Only projects in this lifecycle state.","name":"status","in":"query"},{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"Only projects of this client contact."},"required":false,"description":"Only projects of this client contact.","name":"clientId","in":"query"},{"schema":{"type":"string","description":"Full-text search over project names and descriptions."},"required":false,"description":"Full-text search over project names and descriptions.","name":"search","in":"query"}],"responses":{"200":{"description":"List projects","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectPage"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `read` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createProject","summary":"Create a project","description":"Creates a project in the `planned` state and assigns you to it at `billableRate`. Only team owners and admins can manage projects. `clientId` must be a contact marked as a client.","tags":["Projects"],"security":[{"ApiKey":[]},{"OAuth2":["write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProject"}}}},"responses":{"201":{"description":"Create a project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDetail"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `write` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The record is in a state that blocks this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/projects/{projectId}":{"get":{"operationId":"getProject","summary":"Get a project","description":"Returns one project with its assigned team members. Members’ hourly rates are shown only to team owners and admins.","tags":["Projects"],"security":[{"ApiKey":[]},{"OAuth2":["read"]}],"parameters":[{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":true,"name":"projectId","in":"path"}],"responses":{"200":{"description":"Get a project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDetail"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `read` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateProject","summary":"Update a project","description":"Changes the fields sent and keeps the rest; `null` clears an optional field. Set `status` to move the project through its lifecycle: `completed` and `cancelled` close it, and a closed project must be reopened (in the same request is fine) before its other fields change. The client and currency cannot change once time is tracked. Only team owners and admins can manage projects.","tags":["Projects"],"security":[{"ApiKey":[]},{"OAuth2":["write"]}],"parameters":[{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":true,"name":"projectId","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProject"}}}},"responses":{"200":{"description":"Update a project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDetail"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `write` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The record is in a state that blocks this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/projects/{projectId}/tasks":{"get":{"operationId":"listTimeTasks","summary":"List a project’s tasks","description":"Lists the reusable tasks of a project that time is logged against, up to 200, all on one page. Archived tasks are left out unless `includeArchived` is `true`.","tags":["Time"],"security":[{"ApiKey":[]},{"OAuth2":["read"]}],"parameters":[{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":true,"name":"projectId","in":"path"},{"schema":{"type":"boolean","description":"Also return archived tasks."},"required":false,"description":"Also return archived tasks.","name":"includeArchived","in":"query"}],"responses":{"200":{"description":"List a project’s tasks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeTaskPage"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `read` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createTimeTask","summary":"Create a task","description":"Adds a reusable task to an open project. Names are unique within a project, ignoring case and spacing, and a project holds at most 200 tasks.","tags":["Time"],"security":[{"ApiKey":[]},{"OAuth2":["write"]}],"parameters":[{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":true,"name":"projectId","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTimeTask"}}}},"responses":{"201":{"description":"Create a task","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeTask"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `write` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The record is in a state that blocks this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/time-entries":{"get":{"operationId":"listTimeEntries","summary":"List time entries","description":"Lists time entries that start between `from` and `to`, at most 62 days apart, with their project, task, client and member. Returns up to 1000 entries; `truncated` is `true` when more matched, so narrow the range or filter. Members only see their own entries, and only owners and admins see billable rates.","tags":["Time"],"security":[{"ApiKey":[]},{"OAuth2":["read"]}],"parameters":[{"schema":{"type":"string","format":"date-time","example":"2026-10-11T09:30:00Z","description":"Entries starting at or after this time."},"required":true,"description":"Entries starting at or after this time.","name":"from","in":"query"},{"schema":{"type":"string","format":"date-time","example":"2026-10-11T09:30:00Z","description":"Entries starting before this time; at most 62 days after `from`."},"required":true,"description":"Entries starting before this time; at most 62 days after `from`.","name":"to","in":"query"},{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":false,"name":"projectId","in":"query"},{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":false,"name":"clientId","in":"query"},{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e","description":"Only this member’s entries. Owners and admins only; members always get their own."},"required":false,"description":"Only this member’s entries. Owners and admins only; members always get their own.","name":"memberId","in":"query"},{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":false,"name":"taskId","in":"query"},{"schema":{"type":"boolean","description":"Only billable (`true`) or non-billable (`false`) time."},"required":false,"description":"Only billable (`true`) or non-billable (`false`) time.","name":"billable","in":"query"}],"responses":{"200":{"description":"List time entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeEntryList"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `read` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createTimeEntry","summary":"Log completed time","description":"Records a completed entry for the caller on an active task of a project they are assigned to. Billable minutes follow the project’s rounding, and billable time takes the caller’s project rate, which must be set.","tags":["Time"],"security":[{"ApiKey":[]},{"OAuth2":["write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTimeEntry"}}}},"responses":{"201":{"description":"Log completed time","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeEntry"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `write` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The record is in a state that blocks this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/time-entries/{entryId}":{"patch":{"operationId":"updateTimeEntry","summary":"Update a time entry","description":"Changes the fields sent on a completed entry and keeps the rest, recalculating minutes and the rate snapshot. Members can only edit their own entries; owners and admins can edit anyone’s and move an entry to another assigned member with `memberId`. Stop a running timer before editing it.","tags":["Time"],"security":[{"ApiKey":[]},{"OAuth2":["write"]}],"parameters":[{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":true,"name":"entryId","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTimeEntry"}}}},"responses":{"200":{"description":"Update a time entry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeEntry"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `write` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The record is in a state that blocks this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteTimeEntry","summary":"Delete a time entry","description":"Permanently deletes a time entry, running or completed. Members can only delete their own entries; owners and admins can delete anyone’s.","tags":["Time"],"security":[{"ApiKey":[]},{"OAuth2":["write"]}],"parameters":[{"schema":{"type":"string","minLength":1,"example":"k578ekb0t4kstn4rfc4qx4mwgn8bep1e"},"required":true,"name":"entryId","in":"path"}],"responses":{"200":{"description":"Delete a time entry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Deleted"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `write` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The record is in a state that blocks this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/timer":{"get":{"operationId":"getTimer","summary":"Get the running timer","description":"Returns the caller’s running timer entry, or `entry: null` when no timer is running. Each member has at most one.","tags":["Time"],"security":[{"ApiKey":[]},{"OAuth2":["read"]}],"responses":{"200":{"description":"Get the running timer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Timer"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `read` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/timer/start":{"post":{"operationId":"startTimer","summary":"Start a timer","description":"Starts a timer for the caller now on an active task of a project they are assigned to, and returns the running entry. Fails with `TIME_TIMER_RUNNING` if one is already running.","tags":["Time"],"security":[{"ApiKey":[]},{"OAuth2":["write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartTimer"}}}},"responses":{"201":{"description":"Start a timer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeEntry"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `write` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The record is in a state that blocks this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/timer/stop":{"post":{"operationId":"stopTimer","summary":"Stop the timer","description":"Stops the caller’s running timer now and returns the completed entry with its rounded minutes. Fails with `TIME_TIMER_NOT_FOUND` when no timer is running.","tags":["Time"],"security":[{"ApiKey":[]},{"OAuth2":["write"]}],"responses":{"200":{"description":"Stop the timer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeEntry"}}}},"400":{"description":"The request is invalid; `message` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The credential is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks the `write` scope, or your role cannot do this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"A record the request names was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The record is in a state that blocks this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests; retry after `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{}}