openapi: 3.0.3 info: title: Apperio API Documentation Analytics E-billing API description: "# Introduction\n\nThe Apperio API allows law firms and businesses to enhance their internal\nbusiness intelligence capabilities. These APIs are designed to efficiently support\ninteractive reporting and are used to power the Apperio application.\n\n# API Versioning\n\nMajor versions will come with semantic versioning guarantees.\nThat is to say, there will be no breaking changes in minor version upgrades.\nIn particular the following changes will only be introduced in major versions of the API:\n\n * Changing the meaning of an entity or attribute\n * Renaming entities or attributes\n * Adding new required attributes in the request\n * Changing the URI of the endpoint\n * Removing a URI endpoint\n * Adding further choices to an enumeration\n * Removing choices from an enumeration in the request\n\nFurther endpoints and entity attributes can be added in minor versions. It's expected that\nclients should ignore any attributes that are returned in the response that they weren't\naware of. When a multiple option attribute isn't modelled with an explicit enumeration the\nintegrating clients should also ensure that they can handle unknown responses.\n\nEach previous version of the API will be supported for 6 months after the release of a new\nmajor version. A migration plan will be published for each major version to inform integrators\nof breaking changes.\n\n### What is likely to change in the next major version of the API?\n\n#### Service Versioning\n\nEach endpoint will include the version and service name. Endpoints will have the following format:\n\n`/api/v[MAJOR VERSION NUMBER]/[SERVICE_NAME]/[ENDPOINT NAME]`\n\nHence in version 2:\n\n* `/api/v1/filter/invoices/` will change to `/api/v2/filter/invoices/`\n* `/api/v1/analytics/` will change to `/api/v2/analytics/analytics/`\n\n#### Matter / Engagement\n\nThe terms matter and engagement are used interchangeably in the current version. This\nreflects historical usage in the product. References to `engagement` will be replaced\nwith `matter` in future versions.\n\n# Change Log for Version 1.5\n\n#### v1.5\n* Updated engagement and invoice filter endpoints parameters documentation\n* Added documentation for some ebilling endpoints\n\n#### v1.4\n* Added basic information about the matter header endpoint\n\n#### v1.3\n* Update rate limits\n* Fix analytics URL and auhorization header\n\n#### v1.2\n* Key Management\n* HTTP 429 response\n* Versioning moved from service to global API version\n* Glossary definitions\n\n#### v1.1\n* Matter Tag Set Discovery Endpoint\n\n#### v1.0\n* Versioning Strategy\n* Glossary\n\n#### v0.2\n\n* Invoice discovery endpoint.\n* Null choice filter.\n* Fair usage policy.\n* Capabilities for law firm and business users.\n\n#### v0.1\n\n* Filter resource discovery API.\n\n# Authentication\n\nAll endpoints require that you be authenticated. To become authenticated\nyou will need to create an API Key from the profile page in the application,\nand supply it within the Authentication header in the following format:\n\n```\ncurl -X GET \"https://sandbox.apperio.com/api/v1/data/analytics/\"\n-H \"Authorization: Token \"\n```\n\nPlease contact Customer Success to enable API access on your account.\n\nAll requests that are made to the API will be made with the capabilities of\nthe user generating the token. It's important that you ensure that the access\ntoken is kept secret and not shared outside of your organisation. In particular\nbe mindful not to check it in to code or configuration files where it can be\nseen in plain text. We recommend cycling the API key at least every 12 months.\nIf you suspect that the key may been leaked then disable it immediately in the profile\nsection and inform Apperio. Apperio do not have access to these tokens; hence, you\nwill need to generate a new token if it's lost.\n\nYou should consider that this token grants access to anything that the associated\nuser can access on the website. This will allow you to take advantage of future\nendpoints without further configuration. With this in mind be careful to give this\naccount the minimum set of privileges required for your integration.\n\n# Pagination and Ordering\n\nPagination endpoints allow ordered data to be brought back in chunks. Pagination\nis usually limited to data discovery and information feed endpoints. If available\n`PAGINATION` will be listed in the *Capabilities* section of the endpoint. The response\ncan be ordered by setting the `ordering` query parameter. This takes a URL encoded\ncomma separated list of fields to order by. If a field is prepended by a `-` then\nthe ordering is reversed. For example if I wished to order by `last_worked_at_law_firm`\nwith the latest results first and then by `engagement_id` I would add the following\nto the query:\n\n```\nordering=-last_worked_at_law_firm%2Cengagement_id\n```\n\nThe number of results returned on a page is controlled by the `page-size` parameter.\nIt defaults to 50 across the API and will be capped to avoid large one-time data\nextractions that may be prone to fail.\n\n```\nordering=-last_worked_at_law_firm%2Cengagement_id&page-size=10\n```\n\nWhen there are more items to return than can be shown on one page then a pagination\nobject is returned in the response:\n\n```json\n\"pagination\": {\n \"next\": \"https://sandbox.apperio.com/api/v1/filter/engagements/?ordering=-last_worked_at_law_firm%2Cengagement_id&page=dj0yJnA9MiZnPWJiNTdmMDg2NzI2YzQxYWRhZmI4NmZjMjRlODI5ZTIz&page-size=10\",\n \"previous\":null\n \"nextPage\":\"dj0yJnA9MiZnPWJiNTdmMDg2NzI2YzQxYWRhZmI4NmZjMjRlODI5ZTIz\",\n \"previousPage\":null\n}\n```\n\nThe `nextPage` and `previousPage` provide a token that can be passed to the `page` parameter to\nnavigate to that page. `null` indicates that there is no further data in that direction. The `next` and\n`previous` attributes provide HATEOAS style links to navigate to the next and previous page.\n\n# Business and Law Firm Capabilities\n\nApperio is a double sided platform that allows law firms and businesses to collaborate. The Apperio API is available\nto both businesses and law firms; however some requests are only available to one side of the platform. The capabilities\nsection for each endpoint details which side can access each API call.\n\nThe access token serves to identify the organisation (law firm or business). Resources in each request will be restricted\nto those available to that organisation.\n\n# Acceptable usage policy\n\n* Please respect the usage limits. If you think you are likely to exceed them then please contact Customer Success.\n The standard usage limits are:\n - Requests from the same authorization token should be made in series; not in parallel\n - Maximum of 10000 requests in an hour\n* The API is designed to allow you to provide innovative services that incorporate data that's held in Apperio.\nThey should not be used as a means of duplicating that data.\n* If you're unsure about the most effective way to integrate with Apperio to support your business case then\nplease contact Customer Success so we can take you through different solutions.\n* Your application must be able to handle a `HTTP 429 Too Many Requests` response.\n* Apperio reserve the right to suspend API access if usage contravenes this policy. \n\n# Glossary\n\nThe following terminology is used throughout the API\n\n| Term | Description |\n| ------------- | ------------- |\n| Billable | The billable amount includes both entries that have been billed and the potential contribution from work that's in progress. |\n| Billed | The amount that has already been invoiced. |\n| Budget | The estimated budgeted amount for hourly matters. For fixed matters this represents the fixed cost. This also represents the cap for capped matters (see Fee Structure). |\n| Client | The client of the law firm. Multiple law firm clients can be associated with the one Apperio business. |\n| Disbursement | disbursements, hard cost and soft costs. |\n| Engagement | (see Matter) The term `engagement` is Apperio internal terminology for `matter` and will be replaced with `matter` in the next major version. |\n| Fee | The charge for work undertaken by the law firm. |\n| Fee Structure | How the matter will be billed. Apperio supports Hourly, Capped and Fixed Fee structures. |\n| Matter | A law firm case. |\n| Practice Group | The division in the law firm conducting the work. |\n| Wip | Work that has been carried out but not yet billed on the matter (Work in progress). |\n" servers: - url: https://sandbox.apperio.com/ - url: https://app.apperio.com/ tags: - name: E-billing description: 'The e-billing endpoints provide access to the e-billing invoices in Apperio. They allow you to retrieve information about the invoices and the approval workflow, and also to approve and reject invoices. ' paths: /api/v1/ebilling/invoices/{invoice-id}/: get: summary: Get the invoice details description: 'Capabilities: BUSINESS, LAW_FIRM ' tags: - E-billing parameters: - name: invoice-id in: path schema: type: int description: Invoice ID example: 12345 responses: '200': description: 'Invoice details ' content: application/json: schema: type: object description: 'An e-billing invoice that has been submitted to Apperio for processing. ' required: - name properties: id: type: int description: Apperio identifier for the e-billing invoice example: 12345 readOnly: true law_firm_id: type: int description: Apperio identifier for the law firm example: 12345 readOnly: true law_firm_reference: type: string description: The law firm's reference for the invoice. Also known as the invoice number. example: LF-INV-12345 service_provider_type: type: string description: The type of service provider that submitted the invoice. example: legal enum: - legal - accountancy status: type: string example: ebilled description: 'Tracks the progress of an invoice in Apperio: * `draft`: draft invoice that hasn''t yet been billed * `queried`: Invoice that has been billed but queried by the business * `ebilled`: Billed but not yet paid * `in_review`: Business are reviewing the invoice * `approved`: Business has approved * `paid`: Business has paid * `cancelled`: The invoice has been cancelled (AKA voided) ' enum: - draft - queried - ebilled - in_review - approved - paid - cancelled status_changed_automatically: type: boolean description: 'Indicates whether the status was changed automatically by Apperio. If `false`, the status was changed manually by a user. Status can be changed automatically by Apperio when an invoice was queried for a certain number of days and no action was taken. Apperio will then automatically change the status to `cancelled`. ' example: true void_queried_at: type: string format: date-time description: 'Capabilities: LAW_FIRM The date and time the invoice will be voided after being queried for a certain number of days. ' example: '2021-01-01T00:00:00Z' void_queried_in_days: type: integer nullable: true description: 'Capabilities: LAW_FIRM Number of days, counting from the current date, after which the invoice will be voided automatically if it remains in the `queried` status. It is a dynamic field, calculated as the difference between `void_queried_at` and the current date. Only populated if the invoice is in the `queried` status. ' example: 30 has_been_ebilled: type: boolean description: 'Indicates whether the invoice has been e-billed. This is `true` for all invoices that are not in the `draft` status. ' example: true has_breakdown: type: boolean description: 'Indicates whether the invoice has a breakdown of fees and disbursements. This is `true` for invoices where the law firm has provided a breakdown of fees and disbursements, either via a Data File Uploader or a LEDES file. In case of the DFU, the data must also match the values entered for the invoice. ' example: true custom_upload_id: type: int description: 'The identifier for the custom upload that represents the LEDES file used to create the invoice. ' example: 12345 date: type: string format: date description: 'The date the invoice was created in the service provider''s system. ' example: '2021-01-01' tax_date: type: string format: date description: 'The date that should be used for tax purposes. ' example: '2021-01-01' tax_type: type: string description: 'The type of tax that should be applied to the invoice. ' example: VAT billing_start_date: type: string format: date description: 'The start date of the billing period covered by the invoice. ' example: '2021-01-01' billing_end_date: type: string format: date description: 'The end date of the billing period covered by the invoice. ' example: '2021-01-31' currency: allOf: - type: string example: GBP description: ISO 4217 Three letter currency code minLength: 3 maxLength: 3 description: 'ISO 4217 Three letter currency code of the currency that the invoice is billed in. ' net_fees: type: string format: decimal description: 'The total amount of fees billed on the invoice, excluding tax. ' example: '1000.00' net_disbursements: type: string format: decimal description: 'The total amount of disbursements billed on the invoice, excluding tax. ' example: '100.00' net_total: type: string format: decimal description: 'The total amount billed (fees + disbursements) on the invoice, excluding tax. ' example: '1100.00' tax_total: type: string format: decimal description: 'The total amount of tax billed on the invoice. ' example: '220.00' total: type: string format: decimal description: 'The total amount billed on the invoice, including tax. ' example: '1320.00' matters: type: array items: type: object description: 'The invoice matter details ' properties: engagement_id: type: int description: 'The Apperio identifier of the matter that the invoice is associated with. ' example: 12345 client_id: type: int description: 'The Apperio identifier of the client that the invoice is associated with. ' example: 12345 law_firm_reference: type: string description: 'The law firm reference for the matter. ' example: '12345' name: type: string description: 'The name of the matter. ' example: Land Aquisition billing_entity: type: string description: 'The name of the entity that the invoice is billed to. ' example: Acme Corporation net_fees: type: string format: decimal description: 'The total amount of fees billed on the invoice, excluding tax. ' example: '1100.00' net_disbursements: type: string format: decimal description: 'The total amount of disbursements billed on the invoice, excluding tax. ' example: '220.00' description: 'Capabilities: LAW_FIRM The matters that the invoice is associated with. ' matter_ids: type: array items: type: integer description: 'The Apperio identifiers of the matters that the invoice is associated with. ' example: - 12345 - 67890 client_id: type: int description: 'The Apperio identifier of the client that the invoice is associated with. ' example: 12345 billing_entity: type: string description: 'The name of the entity that the invoice is billed to. ' example: Acme Corporation document: allOf: - &id001 type: object description: 'A `document` referenced from the invoice or credit note. Use the document management APIs to retrieve the full document details. ' properties: id: type: string format: uuid description: 'The Apperio identifier of the document object. ' example: 123e4567-e89b-12d3-a456-426614174000 version: type: int description: 'The `version` of the document. ' example: 123 filename: type: string description: 'The name of the file. ' example: Invoice.pdf description: 'The PDF file attached to the invoice. ' credit: type: object description: 'Credit notes associated with an invoice. ' properties: id: type: int description: 'The Apperio identifier of the credit note. ' example: 12345 law_firm_id: type: int description: 'The Apperio identifier of the law firm that the credit note is associated with. ' example: 12345 law_firm_reference: type: string description: 'The law firm reference for the credit note. ' example: '12345' invoice_id: type: int description: 'The Apperio identifier of the e-billing invoice that the credit note is associated with. ' example: 12345 is_cancelled: type: boolean description: 'Whether the credit note has been cancelled. ' example: false date: type: string format: date description: 'The date the credit note was created. ' example: '2020-01-01' refunded_fee: type: string format: decimal description: 'The total amount of fees refunded on the credit note. ' example: '1100.00' refunded_disbursement: type: string format: decimal description: 'The total amount of disbursements refunded on the credit note. ' example: '220.00' refunded_tax: type: string format: decimal description: 'The total amount of tax refunded on the credit note. ' example: '220.00' has_been_ebilled: type: boolean description: 'Whether the credit note has been e-billed. ' example: false document: allOf: - *id001 description: 'The PDF file attached to the credit note. ' source: type: string description: 'The source of the invoice. ' enum: - ledes - pdf example: ledes approved_email_sent_at: type: string format: date-time description: 'The date and time the email was sent to the business to notify them that the invoice has been approved. ' example: '2021-01-01T00:00:00Z' approved_email_sent_to: type: string description: 'The email address the email was sent to. ' example: john.smith@eample.com is_manual: type: boolean description: 'Indicates whether the invoice was created by a "manual" law firm. ' example: false payable: type: string format: decimal description: 'The total amount that is payable on the invoice. ' example: '1320.00' approval_query: type: object description: 'A record of status changes for an e-billing invoice. ' properties: created: type: string format: date-time description: 'The date and time the status change was recorded. ' example: '2021-01-01T00:00:00Z' approver: type: object description: 'A user who can approve an invoice. ' properties: id: type: int description: 'The Apperio identifier of the approver. ' example: 12345 first_name: type: string description: 'The first name of the approver. ' example: John last_name: type: string description: 'The last name of the approver. ' example: Doe email: type: string description: 'The email address of the approver. ' example: john.doe@example.com client_name: type: string description: 'The name of the client that the invoice was submitted to, as set on the invoice at the time of the status change. ' example: Acme Corporation notes: type: string description: 'Any notes that were added to the status change. ' example: Looks good to me! permissions: type: object description: 'The permissions that the user has for the invoice. ' properties: can_edit_data: type: boolean description: 'Indicates whether the user can edit the data on the invoice. ' example: true can_edit_document: type: boolean description: 'Indicates whether the user can edit the document attached to the invoice. ' example: false example: can_edit_data: true can_edit_document: false capabilities: type: object description: 'The optional features available for the invoice. ' properties: has_approval_workflow: type: boolean description: 'Indicates whether the invoice has an approval workflow. ' example: true example: has_approval_workflow: true withheld_fees: type: string format: decimal description: 'The total amount of fees that have been withheld from the invoice. Only present on invoices with an approval workflow. *NOTE: This field is specific to Qatar''s withholding tax laws.* ' example: '100.00' withheld_user: type: object description: 'The user that entered the withheld fees. Only present on invoices with an approval workflow. *NOTE: This field is specific to Qatar''s withholding tax laws.* ' properties: id: type: int description: 'The Apperio identifier of the user. ' example: 12345 first_name: type: string description: 'The first name of the user. ' example: John last_name: type: string description: 'The last name of the user. ' example: Smith email: type: string description: 'The email address of the user. ' example: john.smith@example.com withheld_date: type: string format: date description: 'The date the withheld fees were entered. Only present on invoices with an approval workflow. *NOTE: This field is specific to Qatar''s withholding tax laws.* ' example: '2021-01-01' withheld_notes: type: string description: 'The notes entered when the withheld fees were entered. Only present on invoices with an approval workflow. *NOTE: This field is specific to Qatar''s withholding tax laws.* ' example: Withheld for Qatar tax attributes: type: object description: 'An object mapping attribute names to their values ' example: requester_name: Jane Doe requester_email: jane.doe@example.com '401': description: 'Unauthenticated access - ensure to create a valid API token ' '403': description: 'Unauthorized access - Ensure your organisation owns this invoice and the user has access to it ' '404': description: 'Invoice not found ' /api/v1/ebilling/invoices/{invoice-id}/status/: post: summary: Change invoice status description: 'Capabilities: BUSINESS, LAW_FIRM ' tags: - E-billing parameters: - name: invoice-id in: path schema: type: int description: Invoice ID example: 12345 requestBody: required: true content: application/json: schema: type: object properties: status: &id002 type: string example: ebilled description: 'Tracks the progress of an invoice in Apperio: * `draft`: draft invoice that hasn''t yet been billed * `queried`: Invoice that has been billed but queried by the business * `ebilled`: Billed but not yet paid * `in_review`: Business are reviewing the invoice * `approved`: Business has approved * `paid`: Business has paid * `cancelled`: The invoice has been cancelled (AKA voided) ' enum: - draft - queried - ebilled - in_review - approved - paid - cancelled resolve_queried_notes: type: string description: 'Notes to resolve the queried status ' example: We've resolved all the queries on the invoice resolve_queried_update_type: &id003 type: string description: 'The type of update to the invoice to resolve the queried status The following types are accepted: * `no_change` - Nothing changed * `file_only` - Only the file * `data_only` - Only the data * `file_and_data` - Both the file and the data ' enum: - no_change - file_only - data_only - file_and_data responses: '200': description: 'Invoice status ' content: application/json: schema: type: object description: 'The response to a request to update the status of an invoice. ' properties: status: *id002 resolve_queried_notes: type: string description: 'Notes about the resolution of any queries on the invoice. ' example: All queries resolved. resolve_queried_update_type: *id003 '401': description: 'Unauthenticated access - ensure to create a valid API token ' '403': description: 'Unauthorized access - Ensure your organisation owns this invoice and the user has access to it ' '404': description: 'Invoice not found ' /api/v1/ebilling/invoices/{invoice-id}/approval-workflow/: get: summary: Get information about the invoice's approval workflow description: 'Capabilities: BUSINESS ' tags: - E-billing parameters: - name: invoice-id in: path schema: type: int description: Invoice ID example: 12345 responses: '200': description: 'Invoice approval workflow ' content: application/json: schema: type: object description: 'Invoice approval workflow details. ' properties: invoice_approval_states: type: array description: 'The states that the invoice can be in during the approval workflow. ' items: type: object description: 'An invoice approval state ' properties: id: type: int description: 'The Apperio identifier of the invoice approval state. ' example: 12345 approval_state_id: type: int description: 'The Apperio identifier of the approval state. ' example: 12345 approver: &id004 type: object description: 'A user who can approve an invoice. ' properties: id: type: int description: 'The Apperio identifier of the approver. ' example: 12345 first_name: type: string description: 'The first name of the approver. ' example: John last_name: type: string description: 'The last name of the approver. ' example: Doe email: type: string description: 'The email address of the approver. ' example: john.doe@example.com assigned_approver: *id004 step: type: int description: 'The step in the approval process. ' example: 3 reviewed_at: type: string format: date-time nullable: true description: 'The date and time that this step of the approval process was reviewed (approved, rejected, or queried). `null` if the step has not been reviewed yet. ' example: '2021-01-01T00:00:00Z' was_approved: type: boolean nullable: true description: 'Whether this step of the approval process was approved. `true` if approved, `false` if rejected or queried, `null` if not yet reviewed. ' example: true notes: type: string nullable: true description: 'Notes about this step of the approval process. Required when rejecting, querying, or adjusting the invoice. Optional when approving. ' example: Looks good to me invoice_status: type: string description: 'The status of the invoice at the time in which the state is created. Only populated in some cases. ' example: in_review tracker_states: type: array description: 'The states that the invoice tracker can be in during the approval workflow. ' items: type: object description: 'The invoice state as displayed in the invoice tracker in the Apperio platform. ' properties: short_name: type: string description: 'The short name of the invoice state. ' example: GC state: type: string description: "The state of this step in the invoice approval workflow.\nThis is one of:\n * `approved` - The invoice is already past this step.\n * `review` - The invoice is currently at this step.\n * `pending` - The invoice is yet to reach this step.\n" enum: - approved - review - pending example: approved stage: type: int description: 'The stage of this step in the invoice approval workflow. This is a number that represents the order of the steps in the workflow. ' example: 3 deprecated: true current_step: type: int description: 'The current step in the approval workflow. References the `step` property in the `invoice_approval_states` array. ' example: 3 permissions: type: object description: 'The permissions that the user has for the invoice. ' properties: can_approve: type: boolean description: 'Whether the user can approve, reject or query the invoice. ' example: true rejection_next_step: type: int description: "The next step in the approval workflow if the invoice is rejected.\n\nThis can be one of two values:\n * 0 - the invoice will be moved back to the beginning of the approval workflow when rejected\n * 1 - the invoice will be moved to the previous step in the approval workflow when rejected\n" enum: - 0 - 1 example: 0 invoice_total: type: string format: decimal description: 'The total amount that is payable on the invoice. ' example: '1320.00' payable: type: string format: decimal description: 'The total amount that is payable on the invoice. ' example: '1320.00' withheld_fees: type: string format: decimal description: 'The total amount of fees that have been withheld from the invoice. *NOTE: This field is specific to Qatar''s withholding tax laws.* ' example: '100.00' withheld_user_id: type: int description: 'The user ID that entered the withheld fees. *NOTE: This field is specific to Qatar''s withholding tax laws.* ' example: 12345 withheld_date: type: string format: date description: 'The date the withheld fees were entered. *NOTE: This field is specific to Qatar''s withholding tax laws.* ' example: '2021-01-01' '401': description: 'Unauthenticated access - ensure to create a valid API token ' '403': description: 'Unauthorized access - Ensure your organisation owns this invoice and the user has access to it ' '404': description: 'Invoice not found ' /api/v1/ebilling/invoices/{invoice-id}/approval-state/{invoice-approval-state-id}/approve/: post: summary: Approve the invoice description: 'Capabilities: BUSINESS ' tags: - E-billing parameters: - name: invoice-id in: path schema: type: int description: Invoice ID example: 12345 - name: invoice-approval-state-id in: path schema: type: int description: Invoice Approval State ID example: 12345 responses: '200': description: 'Invoice approved ' content: application/json: schema: type: object description: 'An invoice approval state ' properties: id: type: int description: 'The Apperio identifier of the invoice approval state. ' example: 12345 approval_state_id: type: int description: 'The Apperio identifier of the approval state. ' example: 12345 approver: &id005 type: object description: 'A user who can approve an invoice. ' properties: id: type: int description: 'The Apperio identifier of the approver. ' example: 12345 first_name: type: string description: 'The first name of the approver. ' example: John last_name: type: string description: 'The last name of the approver. ' example: Doe email: type: string description: 'The email address of the approver. ' example: john.doe@example.com assigned_approver: *id005 step: type: int description: 'The step in the approval process. ' example: 3 reviewed_at: type: string format: date-time nullable: true description: 'The date and time that this step of the approval process was reviewed (approved, rejected, or queried). `null` if the step has not been reviewed yet. ' example: '2021-01-01T00:00:00Z' was_approved: type: boolean nullable: true description: 'Whether this step of the approval process was approved. `true` if approved, `false` if rejected or queried, `null` if not yet reviewed. ' example: true notes: type: string nullable: true description: 'Notes about this step of the approval process. Required when rejecting, querying, or adjusting the invoice. Optional when approving. ' example: Looks good to me invoice_status: type: string description: 'The status of the invoice at the time in which the state is created. Only populated in some cases. ' example: in_review '401': description: 'Unauthenticated access - ensure to create a valid API token ' '403': description: 'Unauthorized access - Ensure your organisation owns this invoice and the user has access to approve it ' '404': description: 'Invoice not found ' /api/v1/ebilling/invoices/{invoice-id}/approval-state/{invoice-approval-state-id}/reject/: post: summary: Reject the invoice description: 'Capabilities: BUSINESS ' tags: - E-billing parameters: - name: invoice-id in: path schema: type: int description: Invoice ID example: 12345 - name: invoice-approval-state-id in: path schema: type: int description: Invoice Approval State ID example: 12345 requestBody: required: true content: application/json: schema: type: object properties: rejection_next_step: type: string description: "Next step after rejecting the invoice. The following values are accepted:\n * `previous`: Return to the previous state\n * `beginning`: Return to the beginning of the approval workflow\n" enum: - previous - beginning example: previous notes: type: string description: 'Reason for rejecting the invoice ' example: Please provide more details on the invoice responses: '200': description: 'Invoice approved ' content: application/json: schema: allOf: - type: object description: 'An invoice approval state ' properties: id: type: int description: 'The Apperio identifier of the invoice approval state. ' example: 12345 approval_state_id: type: int description: 'The Apperio identifier of the approval state. ' example: 12345 approver: &id006 type: object description: 'A user who can approve an invoice. ' properties: id: type: int description: 'The Apperio identifier of the approver. ' example: 12345 first_name: type: string description: 'The first name of the approver. ' example: John last_name: type: string description: 'The last name of the approver. ' example: Doe email: type: string description: 'The email address of the approver. ' example: john.doe@example.com assigned_approver: *id006 step: type: int description: 'The step in the approval process. ' example: 3 reviewed_at: type: string format: date-time nullable: true description: 'The date and time that this step of the approval process was reviewed (approved, rejected, or queried). `null` if the step has not been reviewed yet. ' example: '2021-01-01T00:00:00Z' was_approved: type: boolean nullable: true description: 'Whether this step of the approval process was approved. `true` if approved, `false` if rejected or queried, `null` if not yet reviewed. ' example: true notes: type: string nullable: true description: 'Notes about this step of the approval process. Required when rejecting, querying, or adjusting the invoice. Optional when approving. ' example: Looks good to me invoice_status: type: string description: 'The status of the invoice at the time in which the state is created. Only populated in some cases. ' example: in_review - type: object properties: rejection_next_step: type: string description: 'Next step after rejecting the invoice. This will be equal to the value sent in the request. ' enum: - previous - beginning example: previous notes: type: string description: 'Reason for rejecting the invoice ' example: Please provide more details on the invoice asdf '401': description: 'Unauthenticated access - ensure to create a valid API token ' '403': description: 'Unauthorized access - Ensure your organisation owns this invoice and the user has access to approve it ' '404': description: 'Invoice not found ' /api/v1/ebilling/invoices/{invoice-id}/approval-state/{invoice-approval-state-id}/adjust/: post: summary: Adjust the payable amount of the invoice description: 'Capabilities: BUSINESS This endpoint allows you to adjust the payable amount of the invoice. It can only be called for approval states that allow adjustments. ' tags: - E-billing parameters: - name: invoice-id in: path schema: type: int description: Invoice ID example: 12345 - name: invoice-approval-state-id in: path schema: type: int description: Invoice Approval State ID example: 12345 requestBody: required: true content: application/json: schema: type: object properties: notes: type: string description: 'Reason for adjusting the invoice amount ' example: We've adjusted the invoice to reflect the correct amount payable: type: string format: decimal description: 'The actual payable amount ' example: '1000.00' responses: '200': description: 'Invoice adjusted ' content: application/json: schema: allOf: - type: object description: 'An invoice approval state ' properties: id: type: int description: 'The Apperio identifier of the invoice approval state. ' example: 12345 approval_state_id: type: int description: 'The Apperio identifier of the approval state. ' example: 12345 approver: &id007 type: object description: 'A user who can approve an invoice. ' properties: id: type: int description: 'The Apperio identifier of the approver. ' example: 12345 first_name: type: string description: 'The first name of the approver. ' example: John last_name: type: string description: 'The last name of the approver. ' example: Doe email: type: string description: 'The email address of the approver. ' example: john.doe@example.com assigned_approver: *id007 step: type: int description: 'The step in the approval process. ' example: 3 reviewed_at: type: string format: date-time nullable: true description: 'The date and time that this step of the approval process was reviewed (approved, rejected, or queried). `null` if the step has not been reviewed yet. ' example: '2021-01-01T00:00:00Z' was_approved: type: boolean nullable: true description: 'Whether this step of the approval process was approved. `true` if approved, `false` if rejected or queried, `null` if not yet reviewed. ' example: true notes: type: string nullable: true description: 'Notes about this step of the approval process. Required when rejecting, querying, or adjusting the invoice. Optional when approving. ' example: Looks good to me invoice_status: type: string description: 'The status of the invoice at the time in which the state is created. Only populated in some cases. ' example: in_review - type: object properties: invoice_total: type: string format: decimal description: 'The total amount of the invoice at the time of adjustment ' example: '1000.00' payable: type: string format: decimal description: 'The actual payable amount ' example: '1000.00' withheld_fees: type: string format: decimal description: 'The amount of fees withheld ' example: '100.00' withheld_user_id: type: int description: 'The user ID of the user who withheld the fees ' example: 12345 '401': description: 'Unauthenticated access - ensure to create a valid API token ' '403': description: 'Unauthorized access - Ensure your organisation owns this invoice and the user has access to approve it ' '404': description: 'Invoice not found ' /api/v1/ebilling/invoices/{invoice-id}/approval-state/{invoice-approval-state-id}/query/: post: summary: Query the invoice description: 'Capabilities: BUSINESS ' tags: - E-billing parameters: - name: invoice-id in: path schema: type: int description: Invoice ID example: 12345 - name: invoice-approval-state-id in: path schema: type: int description: Invoice Approval State ID example: 12345 requestBody: required: true content: application/json: schema: type: object properties: notes: type: string description: 'Reason for querying the invoice ' example: Please provide more details on the invoice responses: '200': description: 'Invoice queried ' content: application/json: schema: allOf: - type: object description: 'An invoice approval state ' properties: id: type: int description: 'The Apperio identifier of the invoice approval state. ' example: 12345 approval_state_id: type: int description: 'The Apperio identifier of the approval state. ' example: 12345 approver: &id008 type: object description: 'A user who can approve an invoice. ' properties: id: type: int description: 'The Apperio identifier of the approver. ' example: 12345 first_name: type: string description: 'The first name of the approver. ' example: John last_name: type: string description: 'The last name of the approver. ' example: Doe email: type: string description: 'The email address of the approver. ' example: john.doe@example.com assigned_approver: *id008 step: type: int description: 'The step in the approval process. ' example: 3 reviewed_at: type: string format: date-time nullable: true description: 'The date and time that this step of the approval process was reviewed (approved, rejected, or queried). `null` if the step has not been reviewed yet. ' example: '2021-01-01T00:00:00Z' was_approved: type: boolean nullable: true description: 'Whether this step of the approval process was approved. `true` if approved, `false` if rejected or queried, `null` if not yet reviewed. ' example: true notes: type: string nullable: true description: 'Notes about this step of the approval process. Required when rejecting, querying, or adjusting the invoice. Optional when approving. ' example: Looks good to me invoice_status: type: string description: 'The status of the invoice at the time in which the state is created. Only populated in some cases. ' example: in_review - type: object properties: notes: type: string description: 'Reason for querying the invoice ' example: Please provide more details on the invoice '401': description: 'Unauthenticated access - ensure to create a valid API token ' '403': description: 'Unauthorized access - Ensure your organisation owns this invoice and the user has access to approve it ' '404': description: 'Invoice not found ' /api/v1/ebilling/invoices/{invoice-id}/attributes/: put: summary: Set the invoice attributes description: 'Capabilities: BUSINESS ' tags: - E-billing parameters: - name: invoice-id in: path schema: type: int description: Invoice ID example: 12345 requestBody: required: true content: application/json: schema: type: object properties: sample_attribute_1: type: string description: 'Sample attribute 1 ' example: Sample value 1 sample_attribute_2: type: string description: 'Sample attribute 2 ' example: Sample value 2 responses: '200': description: 'Invoice details ' content: application/json: schema: type: object description: 'An object mapping invoice attribute names to their values. The actual fields depend on the specific business configuration. ' properties: sample_attribute_1: type: string description: 'Sample attribute 1 ' example: Sample value 1 sample_attribute_2: type: string description: 'Sample attribute 2 ' example: Sample value 2 '400': description: 'Attributes validation failed ' content: application/json: schema: type: object properties: missing_attribute_3: type: array item: string example: - This field is required. '401': description: 'Unauthenticated access - ensure to create a valid API token ' '403': description: 'Unauthorized access - Ensure your organisation owns this invoice and the user has access to it ' '404': description: 'Invoice not found ' /api/v1/ebilling/invoices/business-attributes/: get: summary: List business invoice attributes description: 'Capabilities: BUSINESS Returns all custom invoice attributes configured for the authenticated user''s business, ordered by `order`, then `label`, then `name`. Attributes define the custom fields that can be set on invoices submitted through Apperio. Each attribute''s `name` is used as the key in invoice attribute data and in `attribute_{name}` filter parameters on the invoice filter endpoint. ' tags: - E-billing parameters: - name: show_in_form in: query schema: type: boolean description: Filter attributes by whether they are shown in the invoice submission form responses: '200': description: 'List of attributes ' content: application/json: schema: type: array items: type: object properties: id: type: integer description: Apperio identifier for the attribute example: 42 label: type: string maxLength: 50 description: Human-readable label displayed in forms and the UI example: Cost Center name: type: string maxLength: 50 description: 'Machine-readable field name used as the key in invoice attribute data and in `attribute_{name}` filter parameters. Auto-generated from `label` (lowercased, spaces replaced with underscores) if not provided on creation. Immutable after creation. Must start with a lowercase letter and contain only lowercase letters, numbers, and underscores. ' example: cost_center attr_type: type: string enum: - text - long_text - email - dropdown description: 'The type of the attribute. Immutable after creation. - `text`: short free-text value - `long_text`: multi-line free-text value - `email`: validated email address - `dropdown`: value selected from a predefined list of options ' example: text default_value: type: string description: 'Default value for the attribute. For `dropdown` attributes this is the value of the default option (see `options`). For `email` attributes the value is validated as a valid email address. ' example: CC-0000 placeholder: type: string maxLength: 30 description: Placeholder text shown in the input field example: e.g. CC-1234 show_in_form: type: boolean description: Whether this attribute is shown in the invoice submission form example: true is_required: type: boolean description: 'Whether this attribute is required when submitting an invoice. An attribute can only be required if `show_in_form` is `true`. ' example: true options: type: array nullable: true description: 'List of selectable options. Only present for `dropdown` attributes; `null` for all other types. ' items: type: object properties: id: type: integer description: Apperio identifier for the option example: 101 value: type: string maxLength: 255 description: Display value of the option. Case-insensitively unique per attribute. example: CC-1234 law_firm_ids: type: array description: 'IDs of law firms for which this option is available. An empty list means the option is available to all firms. ' items: type: integer example: - 12 - 34 is_default: type: boolean description: Whether this is the default selected option. At most one option per attribute can be the default. example: false order: type: integer description: Display order of the option (read-only, auto-assigned) example: 1 can_delete: type: boolean description: Whether this option can be deleted. `false` if any invoice currently uses this option value. example: true can_delete: type: boolean description: Whether this attribute can be deleted. `false` if any invoice currently has a value set for this attribute. example: true '401': description: 'Unauthenticated access - ensure to create a valid API token ' '403': description: 'Unauthorized access - endpoint is only available to business users ' post: summary: Create a business invoice attribute description: 'Capabilities: BUSINESS Creates a new custom invoice attribute for the authenticated user''s business. If `name` is not provided it will be auto-generated from `label` (lowercased, spaces replaced with underscores). The `name` and `attr_type` fields are immutable after creation. ' tags: - E-billing requestBody: required: true content: application/json: schema: type: object required: - label - attr_type properties: label: type: string maxLength: 50 description: Human-readable label for the attribute example: Cost Center name: type: string maxLength: 50 description: 'Machine-readable field name. Auto-generated from `label` if omitted. Must start with a lowercase letter and contain only lowercase letters, numbers, and underscores. Must be unique within the business. ' example: cost_center attr_type: type: string enum: - text - long_text - email - dropdown description: The type of the attribute. Immutable after creation. example: text default_value: type: string description: Default value. For `email` types must be a valid email address. example: CC-0000 placeholder: type: string maxLength: 30 description: Placeholder text shown in the input field example: e.g. CC-1234 show_in_form: type: boolean description: Whether to show this attribute in the invoice submission form. Defaults to `true`. example: true is_required: type: boolean description: Whether this attribute is required on submission. Defaults to `true`. Only valid when `show_in_form` is `true`. example: true options: type: array description: Selectable options. Only valid for `dropdown` attributes. items: type: object required: - value properties: value: type: string maxLength: 255 description: Display value of the option. Case-insensitively unique per attribute. example: CC-1234 law_firm_ids: type: array description: IDs of law firms for which this option is available. Empty list means all firms. items: type: integer example: - 12 - 34 is_default: type: boolean description: Whether this is the default option. At most one option per attribute can be the default. example: false responses: '201': description: 'Attribute created ' content: application/json: schema: type: object properties: id: type: integer description: Apperio identifier for the attribute example: 42 label: type: string maxLength: 50 description: Human-readable label displayed in forms and the UI example: Cost Center name: type: string maxLength: 50 description: 'Machine-readable field name used as the key in invoice attribute data and in `attribute_{name}` filter parameters. Auto-generated from `label` (lowercased, spaces replaced with underscores) if not provided on creation. Immutable after creation. Must start with a lowercase letter and contain only lowercase letters, numbers, and underscores. ' example: cost_center attr_type: type: string enum: - text - long_text - email - dropdown description: 'The type of the attribute. Immutable after creation. - `text`: short free-text value - `long_text`: multi-line free-text value - `email`: validated email address - `dropdown`: value selected from a predefined list of options ' example: text default_value: type: string description: 'Default value for the attribute. For `dropdown` attributes this is the value of the default option (see `options`). For `email` attributes the value is validated as a valid email address. ' example: CC-0000 placeholder: type: string maxLength: 30 description: Placeholder text shown in the input field example: e.g. CC-1234 show_in_form: type: boolean description: Whether this attribute is shown in the invoice submission form example: true is_required: type: boolean description: 'Whether this attribute is required when submitting an invoice. An attribute can only be required if `show_in_form` is `true`. ' example: true options: type: array nullable: true description: 'List of selectable options. Only present for `dropdown` attributes; `null` for all other types. ' items: type: object properties: id: type: integer description: Apperio identifier for the option example: 101 value: type: string maxLength: 255 description: Display value of the option. Case-insensitively unique per attribute. example: CC-1234 law_firm_ids: type: array description: 'IDs of law firms for which this option is available. An empty list means the option is available to all firms. ' items: type: integer example: - 12 - 34 is_default: type: boolean description: Whether this is the default selected option. At most one option per attribute can be the default. example: false order: type: integer description: Display order of the option (read-only, auto-assigned) example: 1 can_delete: type: boolean description: Whether this option can be deleted. `false` if any invoice currently uses this option value. example: true can_delete: type: boolean description: Whether this attribute can be deleted. `false` if any invoice currently has a value set for this attribute. example: true '400': description: 'Validation error ' '401': description: 'Unauthenticated access - ensure to create a valid API token ' '403': description: 'Unauthorized access - ensure your account has permission to manage invoice attributes ' /api/v1/ebilling/invoices/business-attributes/{name}/: get: summary: Get a business invoice attribute description: 'Capabilities: BUSINESS Returns the details of a single invoice attribute identified by its `name`. ' tags: - E-billing parameters: - name: name in: path required: true schema: type: string description: The machine-readable name of the attribute example: cost_center responses: '200': description: 'Attribute details ' content: application/json: schema: type: object properties: id: type: integer description: Apperio identifier for the attribute example: 42 label: type: string maxLength: 50 description: Human-readable label displayed in forms and the UI example: Cost Center name: type: string maxLength: 50 description: 'Machine-readable field name used as the key in invoice attribute data and in `attribute_{name}` filter parameters. Auto-generated from `label` (lowercased, spaces replaced with underscores) if not provided on creation. Immutable after creation. Must start with a lowercase letter and contain only lowercase letters, numbers, and underscores. ' example: cost_center attr_type: type: string enum: - text - long_text - email - dropdown description: 'The type of the attribute. Immutable after creation. - `text`: short free-text value - `long_text`: multi-line free-text value - `email`: validated email address - `dropdown`: value selected from a predefined list of options ' example: text default_value: type: string description: 'Default value for the attribute. For `dropdown` attributes this is the value of the default option (see `options`). For `email` attributes the value is validated as a valid email address. ' example: CC-0000 placeholder: type: string maxLength: 30 description: Placeholder text shown in the input field example: e.g. CC-1234 show_in_form: type: boolean description: Whether this attribute is shown in the invoice submission form example: true is_required: type: boolean description: 'Whether this attribute is required when submitting an invoice. An attribute can only be required if `show_in_form` is `true`. ' example: true options: type: array nullable: true description: 'List of selectable options. Only present for `dropdown` attributes; `null` for all other types. ' items: type: object properties: id: type: integer description: Apperio identifier for the option example: 101 value: type: string maxLength: 255 description: Display value of the option. Case-insensitively unique per attribute. example: CC-1234 law_firm_ids: type: array description: 'IDs of law firms for which this option is available. An empty list means the option is available to all firms. ' items: type: integer example: - 12 - 34 is_default: type: boolean description: Whether this is the default selected option. At most one option per attribute can be the default. example: false order: type: integer description: Display order of the option (read-only, auto-assigned) example: 1 can_delete: type: boolean description: Whether this option can be deleted. `false` if any invoice currently uses this option value. example: true can_delete: type: boolean description: Whether this attribute can be deleted. `false` if any invoice currently has a value set for this attribute. example: true '401': description: 'Unauthenticated access - ensure to create a valid API token ' '403': description: 'Unauthorized access - ensure your account has permission to manage invoice attributes ' '404': description: 'Attribute not found ' put: summary: Update a business invoice attribute description: 'Capabilities: BUSINESS Updates an existing invoice attribute. The `name` and `attr_type` fields are immutable and cannot be changed after creation. For `dropdown` attributes, the `options` list is replaced in full on each update — include all options you wish to retain. ' tags: - E-billing parameters: - name: name in: path required: true schema: type: string description: The machine-readable name of the attribute example: cost_center requestBody: required: true content: application/json: schema: type: object properties: label: type: string maxLength: 50 description: Human-readable label for the attribute example: Cost Center default_value: type: string description: Default value. For `email` types must be a valid email address. example: CC-0000 placeholder: type: string maxLength: 30 description: Placeholder text shown in the input field example: e.g. CC-1234 show_in_form: type: boolean description: Whether to show this attribute in the invoice submission form example: true is_required: type: boolean description: Whether this attribute is required on submission. Only valid when `show_in_form` is `true`. example: true options: type: array description: 'Full replacement list of options. Only valid for `dropdown` attributes. Any options omitted from this list will be deleted (only if their `can_delete` is `true`). ' items: type: object required: - value properties: id: type: integer description: ID of an existing option to update. Omit for new options. example: 101 value: type: string maxLength: 255 description: Display value of the option. Case-insensitively unique per attribute. example: CC-1234 law_firm_ids: type: array description: IDs of law firms for which this option is available. Empty list means all firms. items: type: integer example: - 12 - 34 is_default: type: boolean description: Whether this is the default option. At most one option per attribute can be the default. example: false responses: '200': description: 'Attribute updated ' content: application/json: schema: type: object properties: id: type: integer description: Apperio identifier for the attribute example: 42 label: type: string maxLength: 50 description: Human-readable label displayed in forms and the UI example: Cost Center name: type: string maxLength: 50 description: 'Machine-readable field name used as the key in invoice attribute data and in `attribute_{name}` filter parameters. Auto-generated from `label` (lowercased, spaces replaced with underscores) if not provided on creation. Immutable after creation. Must start with a lowercase letter and contain only lowercase letters, numbers, and underscores. ' example: cost_center attr_type: type: string enum: - text - long_text - email - dropdown description: 'The type of the attribute. Immutable after creation. - `text`: short free-text value - `long_text`: multi-line free-text value - `email`: validated email address - `dropdown`: value selected from a predefined list of options ' example: text default_value: type: string description: 'Default value for the attribute. For `dropdown` attributes this is the value of the default option (see `options`). For `email` attributes the value is validated as a valid email address. ' example: CC-0000 placeholder: type: string maxLength: 30 description: Placeholder text shown in the input field example: e.g. CC-1234 show_in_form: type: boolean description: Whether this attribute is shown in the invoice submission form example: true is_required: type: boolean description: 'Whether this attribute is required when submitting an invoice. An attribute can only be required if `show_in_form` is `true`. ' example: true options: type: array nullable: true description: 'List of selectable options. Only present for `dropdown` attributes; `null` for all other types. ' items: type: object properties: id: type: integer description: Apperio identifier for the option example: 101 value: type: string maxLength: 255 description: Display value of the option. Case-insensitively unique per attribute. example: CC-1234 law_firm_ids: type: array description: 'IDs of law firms for which this option is available. An empty list means the option is available to all firms. ' items: type: integer example: - 12 - 34 is_default: type: boolean description: Whether this is the default selected option. At most one option per attribute can be the default. example: false order: type: integer description: Display order of the option (read-only, auto-assigned) example: 1 can_delete: type: boolean description: Whether this option can be deleted. `false` if any invoice currently uses this option value. example: true can_delete: type: boolean description: Whether this attribute can be deleted. `false` if any invoice currently has a value set for this attribute. example: true '400': description: 'Validation error ' '401': description: 'Unauthenticated access - ensure to create a valid API token ' '403': description: 'Unauthorized access - ensure your account has permission to manage invoice attributes ' '404': description: 'Attribute not found ' delete: summary: Delete a business invoice attribute description: 'Capabilities: BUSINESS Deletes an invoice attribute. An attribute can only be deleted if no invoices currently have a value set for it (i.e. `can_delete` is `true` on the attribute). Attempting to delete an attribute that is in use returns `403`. ' tags: - E-billing parameters: - name: name in: path required: true schema: type: string description: The machine-readable name of the attribute example: cost_center responses: '204': description: 'Attribute deleted ' '401': description: 'Unauthenticated access - ensure to create a valid API token ' '403': description: 'Unauthorized access - either your account does not have permission to manage invoice attributes, or the attribute cannot be deleted because it is referenced by one or more invoices (`can_delete` is `false`) ' '404': description: 'Attribute not found '