Skip to content

Create an invoice

POST
/api/Invoices
curl --request POST \
--url https://invoicing-api.eddish.app/api/Invoices \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "clientId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "purchaseOrder": "example", "subject": "example", "notes": "example", "issueDate": "2026-04-15", "paymentTerm": "UponReceipt", "customPaymentTermDays": 1, "tax": 1, "discount": 1, "showHoursSummary": true, "lineItems": [ { "projectId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "kind": "example", "description": "example", "quantity": 1, "unitPrice": 1, "taxed": true } ], "customPaymentTermUnit": "Day" }'

Creates a draft invoice. Admins and Finance only.

Media typeapplication/json

The details of a new draft invoice.

object
clientId
required
string format: uuid
purchaseOrder
required

The client’s purchase order number.

null | string
subject
required
null | string
notes
required
null | string
issueDate
required

The date on the invoice, as yyyy-MM-dd.

string format: date
paymentTerm
required
One of:
null
customPaymentTermDays
required

The length of a Custom payment term, counted in the custom unit.

null | integer | string format: int32
/^-?(?:0|[1-9]\d*)$/
tax
required

The tax rate, as a percentage.

null | number | string format: double
/^-?(?:0|[1-9]\d*)(?:\.\d+)?$/
discount
required

The discount, as a percentage.

null | number | string format: double
/^-?(?:0|[1-9]\d*)(?:\.\d+)?$/
showHoursSummary
required

Whether the invoice prints a summary of hours.

boolean
lineItems
required
Array<object>

The details of an invoice line.

object
projectId
required
null | string format: uuid
kind
required

The label for what the line bills, as free text such as Service or Product.

string
description
required
string
quantity
required

Hours or units charged, as a decimal.

number | string format: double
/^-?(?:0|[1-9]\d*)(?:\.\d+)?$/
unitPrice
required

The price of one hour or unit, in the invoice’s currency.

number | string format: double
/^-?(?:0|[1-9]\d*)(?:\.\d+)?$/
taxed
required

Whether tax applies to the line.

boolean
customPaymentTermUnit
One of:
null

OK

Media typeapplication/json

Shorthand for the overwhelmingly common ServiceResponse&lt;TData, ErrorResponse&gt;. C# cannot alias an open generic, so this is expressed as a subclass rather than a using alias.

object
success

True when the call succeeded and TData? ServiceResponse<TData, TError>.Data is populated.

boolean
data
One of:
null
error
One of:
null

Example

{
"data": {
"state": "Draft",
"paymentTerm": "UponReceipt",
"customPaymentTermUnit": "Day"
}
}

Not signed in, or the credential isn’t recognised, has expired or was revoked: auth.missing_credential, auth.invalid_credential, auth.expired_credential, auth.revoked_credential.

Media typeapplication/json

Shorthand for the overwhelmingly common ServiceResponse&lt;TData, ErrorResponse&gt;. C# cannot alias an open generic, so this is expressed as a subclass rather than a using alias.

object
success

True when the call succeeded and TData? ServiceResponse<TData, TError>.Data is populated.

boolean
data

Payload on success; default on failure.

error

The Framework’s default error shape, used as the TError of ServiceResponse<TData, TError> unless an App genuinely needs its own.

object
code

Stable, machine-readable error identifier (for example account.not_found). Clients branch on this, never on string ErrorResponse.Message.

string
message

Human-readable description of what went wrong. Safe to surface to a User.

string
fieldErrors

Optional per-field validation failures, keyed by field name. Null (and omitted from JSON) for errors that are not validation failures.

null | object
details

Optional machine-readable facts about the failure that a client renders rather than parses out of string ErrorResponse.Message — e.g. plan.limit_reached’s limit, count and planName. Null (and omitted from JSON) for errors that carry none.

null | object

Example generated

{
"success": true,
"data": "example",
"error": {
"code": "example",
"message": "example",
"fieldErrors": "example",
"details": "example"
}
}

Not allowed. error.code says why: auth.role_not_permitted (your role doesn’t allow it), auth.read_only_token (the token can only read), app.no_seat (no seat in this App), auth.api_access_not_in_plan (the plan doesn’t include API access), auth.not_a_member (no longer a member of the Account), auth.insufficient_scope (an Account API key without the scope).

Media typeapplication/json

Shorthand for the overwhelmingly common ServiceResponse&lt;TData, ErrorResponse&gt;. C# cannot alias an open generic, so this is expressed as a subclass rather than a using alias.

object
success

True when the call succeeded and TData? ServiceResponse<TData, TError>.Data is populated.

boolean
data

Payload on success; default on failure.

error

The Framework’s default error shape, used as the TError of ServiceResponse<TData, TError> unless an App genuinely needs its own.

object
code

Stable, machine-readable error identifier (for example account.not_found). Clients branch on this, never on string ErrorResponse.Message.

string
message

Human-readable description of what went wrong. Safe to surface to a User.

string
fieldErrors

Optional per-field validation failures, keyed by field name. Null (and omitted from JSON) for errors that are not validation failures.

null | object
details

Optional machine-readable facts about the failure that a client renders rather than parses out of string ErrorResponse.Message — e.g. plan.limit_reached’s limit, count and planName. Null (and omitted from JSON) for errors that carry none.

null | object

Example generated

{
"success": true,
"data": "example",
"error": {
"code": "example",
"message": "example",
"fieldErrors": "example",
"details": "example"
}
}

The Account is over its plan’s limits, so changes are refused until an Owner or Admin sorts that out: plan.read_only.

Media typeapplication/json

Shorthand for the overwhelmingly common ServiceResponse&lt;TData, ErrorResponse&gt;. C# cannot alias an open generic, so this is expressed as a subclass rather than a using alias.

object
success

True when the call succeeded and TData? ServiceResponse<TData, TError>.Data is populated.

boolean
data

Payload on success; default on failure.

error

The Framework’s default error shape, used as the TError of ServiceResponse<TData, TError> unless an App genuinely needs its own.

object
code

Stable, machine-readable error identifier (for example account.not_found). Clients branch on this, never on string ErrorResponse.Message.

string
message

Human-readable description of what went wrong. Safe to surface to a User.

string
fieldErrors

Optional per-field validation failures, keyed by field name. Null (and omitted from JSON) for errors that are not validation failures.

null | object
details

Optional machine-readable facts about the failure that a client renders rather than parses out of string ErrorResponse.Message — e.g. plan.limit_reached’s limit, count and planName. Null (and omitted from JSON) for errors that carry none.

null | object

Example generated

{
"success": true,
"data": "example",
"error": {
"code": "example",
"message": "example",
"fieldErrors": "example",
"details": "example"
}
}

Too many requests: rate_limit.exceeded. Wait the number of seconds in the Retry-After header.

Media typeapplication/json

Shorthand for the overwhelmingly common ServiceResponse&lt;TData, ErrorResponse&gt;. C# cannot alias an open generic, so this is expressed as a subclass rather than a using alias.

object
success

True when the call succeeded and TData? ServiceResponse<TData, TError>.Data is populated.

boolean
data

Payload on success; default on failure.

error

The Framework’s default error shape, used as the TError of ServiceResponse<TData, TError> unless an App genuinely needs its own.

object
code

Stable, machine-readable error identifier (for example account.not_found). Clients branch on this, never on string ErrorResponse.Message.

string
message

Human-readable description of what went wrong. Safe to surface to a User.

string
fieldErrors

Optional per-field validation failures, keyed by field name. Null (and omitted from JSON) for errors that are not validation failures.

null | object
details

Optional machine-readable facts about the failure that a client renders rather than parses out of string ErrorResponse.Message — e.g. plan.limit_reached’s limit, count and planName. Null (and omitted from JSON) for errors that carry none.

null | object

Example generated

{
"success": true,
"data": "example",
"error": {
"code": "example",
"message": "example",
"fieldErrors": "example",
"details": "example"
}
}
Retry-After
integer

Seconds to wait before trying again.