Skip to content

Prepare a sales invoice, a customer credit note or a customer debit note

POST
/receivables/invoices
curl --request POST \
--url https://example.com/v1/receivables/invoices \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: example' \
--data '{ "attachment_ids": [ "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0" ], "currency": "example", "custom_fields": { "additionalProperty": "example" }, "customer_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "customer_reference": "example", "fx_rate": "4.2000000000", "kind": "sales_invoice", "lines": [ { "account_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "classification_code": "example", "description": "example", "discount_amount": "1234.5600", "quantity": "4.2000000000", "shares": [ { "analytic_account_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "percentage": "4.2000000000" } ], "tax_code_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "tax_exemption_reason": "example", "trade_line_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "unit_code": "example", "unit_price": "1234.5600" } ], "original_invoice_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "payment_terms_days": 1, "reason": "example" }'

Starts as an unnumbered draft (R2). Issuing it is a person’s decision and is not part of the public API. Idempotency-Key is required when sent with an API key. Requires receivables.invoice.create.

Idempotency-Key
required
string
>= 1 characters <= 255 characters

Names this attempt. Required for every write made with an API key: reuse it to retry (the first attempt’s answer is replayed, with Idempotent-Replayed: true, and nothing runs twice); change it for a different request. The same key over a different request is 409 idempotency_key_reused. Keys are kept for 24 hours and are scoped to the API key that sent them.

Media typeapplication/json
object
attachment_ids

Documents the caller uploaded (POST /documents), attached with the record in one step: a refusal (409 document_bound_elsewhere, 422 document_not_yours or document_unknown) rolls the record back. Create only; add later with POST …/attachments. Attachments are never detached, and an update that sends this is refused.

Array<string>
currency
required
string
custom_fields

User-defined field values by key, checked against the active definitions (422 custom_field_invalid, each value at /custom_fields/ in errors). Omitted on an update keeps the stored values; a retired field keeps its value.

object
key
additional properties
string
customer_id
required
string format: uuid
customer_reference
string
<= 64 characters
fx_rate

Required when currency is not the base currency.

string
kind

Read on create; ignored on update.

string
Allowed values: sales_invoice customer_credit_note customer_debit_note
lines
required
Array<object>
>= 1 items <= 200 items
object
account_id
required
string format: uuid
classification_code
required

E-Invoice classification; 022 is Others

string
/^[0-9]{3}$/
description
required
string
<= 500 characters
discount_amount

A decimal amount as a string. Never a JSON number.

string

Example

1234.5600
quantity
required

A decimal rate or percentage as a string, up to 10 places. Never a JSON number.

string

Example

4.2000000000
shares
Array<object>
object
analytic_account_id
required
string format: uuid
percentage
required

A decimal rate or percentage as a string, up to 10 places. Never a JSON number.

string

Example

4.2000000000
tax_code_id
required
string format: uuid
tax_exemption_reason
string
nullable <= 300 characters
trade_line_id

A delivery line (an invoice) or sales return line (a credit note) of this customer; quantity is then in base units (O3.2).

string format: uuid
nullable
unit_code
string
nullable /^[A-Z0-9]{2,3}$/
unit_price
required

A decimal amount as a string. Never a JSON number.

string

Example

1234.5600
original_invoice_id

A credit note’s invoice.

string format: uuid
nullable
payment_terms_days

Absent - the customer’s own terms.

integer
nullable <= 365
reason

A credit note’s reason.

string
nullable <= 500 characters

The document

Media typeapplication/json
object
buyer
required

Frozen when issued; null on a draft.

object
address
required
object
city
string
line1
string
line2
string
postcode
string
state
string
country_code
required
string
nullable
email
required
string
nullable
name
required
string
phone
required
string
nullable
registration_no
required
string
nullable
registration_type
required
string
nullable
sst_no
required
string
nullable
tin
required
string
nullable
created_at
required
string format: date-time
currency
required
string
custom_fields

The organization’s user-defined field values by key (GET /org/custom-fields); {} when none.

object
key
additional properties
string
customer_id
required
string format: uuid
customer_reference
required
string
due_on
required
string format: date
fx_rate
required

A decimal rate or percentage as a string, up to 10 places. Never a JSON number.

string
gross_amount
required

A decimal amount as a string. Never a JSON number.

string
gross_base
required

A decimal amount as a string. Never a JSON number.

string
id
required
string format: uuid
invoice_date
required
string format: date
is_group_transaction
required

True when the party is currently mapped to a company of the organization’s group, so a consolidation run eliminates the dealing. Derived from the party map at read time, never stored on the transaction.

boolean
is_opening

Brought in by a data migration (import M5)

boolean
issued_at
required
string format: date-time
nullable
kind
required
string
Allowed values: sales_invoice customer_credit_note customer_debit_note
legacy_reference

The previous system’s number

string
nullable
lines
required
Array<object>
object
account_id
required
string format: uuid
classification_code
required
string
description
required
string
discount_amount
required

A decimal amount as a string. Never a JSON number.

string
id
required
string format: uuid
line_no
required
integer
net_amount
required

A decimal amount as a string. Never a JSON number.

string
net_base
required

A decimal amount as a string. Never a JSON number.

string
quantity
required

A decimal rate or percentage as a string, up to 10 places. Never a JSON number.

string
shares
required
Array<object>
object
analytic_account_id
required
string format: uuid
percentage
required

A decimal rate or percentage as a string, up to 10 places. Never a JSON number.

string
tax_amount
required

A decimal amount as a string. Never a JSON number.

string
tax_base
required

A decimal amount as a string. Never a JSON number.

string
tax_code
required

The tax code as it read when the line was priced.

string
tax_code_id
required
string format: uuid
tax_exemption_reason
required
string
nullable
tax_pack_kind
required
string
tax_rate
required

A decimal rate or percentage as a string, up to 10 places. Never a JSON number.

string
trade_line_id
required

A delivery line (an invoice) or sales return line (a credit note) of this customer; quantity is then in base units (O3.2).

string format: uuid
nullable
unit_code
required
string
nullable
unit_price
required

A decimal amount as a string. Never a JSON number.

string
multiple_projects
required

True when the lines charge two or more distinct projects.

boolean
net_total
required

A decimal amount as a string. Never a JSON number.

string
original_invoice_id
required
string format: uuid
nullable
original_total

An opening document’s original total, for reference; gross_amount is what was outstanding at the cut-over.

string
outstanding
required

Gross less allocations (a credit note - what it has left).

string
payment_terms_days
required
integer
prepared_by
required
string format: uuid
project
required

The project every project-charged line shares; null when none or when several (see multiple_projects).

object
code
required
string
id
required
string format: uuid
name
required
string
reason
required
string
nullable
reference
required

Null on a draft; numbered when issued (R2).

string
nullable
revision
required
integer
seller
required

Frozen when issued; null on a draft.

object
address
required
string
nullable
msic
required
string
nullable
name
required
string
registration_no
required
string
nullable
sst_no
required
string
nullable
tin
required
string
nullable
semantic
required
string
Allowed values: draft pending accrual payout acknowledged dispute rejected cancelled custom committed effect
state
required
string
tax_total
required

A decimal amount as a string. Never a JSON number.

string
allocations
required
Array<object>
object
amount
required

A decimal amount as a string. Never a JSON number.

string
base_amount
required

A decimal amount as a string. Never a JSON number.

string
created_at
required
string format: date-time
created_by
required
string format: uuid
credit_note_id
required
string format: uuid
nullable
currency
required
string
effective_on
required
string format: date
id
required
string format: uuid
invoice_id
required
string format: uuid
receipt_id
required
string format: uuid
nullable
reversed_by_id
required
string format: uuid
nullable
reverses_id
required
string format: uuid
nullable
source_kind
required
string
Allowed values: receipt credit_note
attachment_ids
required

Documents attached to the record, oldest first; readers are whoever may read the record.

Array<string>
available_transitions
required
Array<object>
object
action_key
required
string
allowed
required
boolean
gate
required
string
Allowed values: reporter target source advance
labels
required

Locale to text. “en” is required; keys are supported UI locales.

object
key
additional properties
string
<= 200 characters
refusal
object
code
required

Not_reporter, no_band_covers_amount, not_in_band, self_approval, dispute_raiser or already_signed (a sign-off step, when the actor has already signed everything they may).

string
detail
required
string
gaps
Array<object>

Reason is one of member_inactive, position_retired, vacant, no_primary_position, no_unit_head, above_root, only_the_claimant, no_band_covers_amount, unallocated (part of the amount carries no account on the step’s axis) or no_account_approver (the account, and every ancestor, has no approver).

object
analytic_account_id
string format: uuid
axis_id
string format: uuid
grant_id
required
string format: uuid
member_id
string format: uuid
position_id
string format: uuid
reason
required
string
requires_reason
required
boolean
signs

The shares this edge lets the actor sign, on a sign-off step.

Array<object>
object
account_code
required
string
account_name
required
string
amount
required

A decimal amount as a string. Never a JSON number.

string
analytic_account_id
required
string format: uuid
axis_id
required
string format: uuid
sole_owner_exception

Allowed only as the sole-owner exception (Ruling O-3a): the organization’s one active member deciding their own sales document. requires_reason is then true, and the decision is recorded with authority_via sole_owner_exception. The reason is English or Bahasa Malaysia, at most 500 characters (422 field=reason otherwise); a blank one is refused with 422 sole_owner_reason_required.

boolean
to
required
string
outstanding
required

Gross less allocations (a credit note - what it has left).

string
outstanding_base
required

A decimal amount as a string. Never a JSON number.

string
timeline
required
Array<object>
object
action_key
required
string
actor_member_id
required
string format: uuid
decided_at
required
string format: date-time
from
required
string
reason
required
string
to
required
string

Example

{
"fx_rate": "4.2000000000",
"gross_amount": "1234.5600",
"gross_base": "1234.5600",
"kind": "sales_invoice",
"lines": [
{
"discount_amount": "1234.5600",
"net_amount": "1234.5600",
"net_base": "1234.5600",
"quantity": "4.2000000000",
"shares": [
{
"percentage": "4.2000000000"
}
],
"tax_amount": "1234.5600",
"tax_base": "1234.5600",
"tax_rate": "4.2000000000",
"unit_price": "1234.5600"
}
],
"net_total": "1234.5600",
"original_total": "1234.5600",
"outstanding": "1234.5600",
"semantic": "draft",
"tax_total": "1234.5600",
"allocations": [
{
"amount": "1234.5600",
"base_amount": "1234.5600",
"source_kind": "receipt"
}
],
"available_transitions": [
{
"gate": "reporter",
"signs": [
{
"amount": "1234.5600"
}
]
}
],
"outstanding_base": "1234.5600"
}
ETag
string

The record’s revision, quoted.

The body is not a single JSON object of this endpoint’s shape: it is missing, malformed, carries a field of the wrong type, or carries a field this endpoint does not accept. Unknown fields are refused, not ignored; the detail names the offending field where there is one.

Media typeapplication/problem+json
object
code

A stable refusal code the client branches on, where the status alone is not enough: owner_role_manage_required and self_lockout on the role editor’s 409s; revision_mismatch (a stale If-Match) and document_bound_elsewhere (the document backs another record) on an expense claim’s 409s.

string
detail
string
instance
string
status
required
integer
title
required
string
type
required
string

Example generated

{
"code": "example",
"detail": "example",
"instance": "example",
"status": 1,
"title": "example",
"type": "example"
}

Not authenticated, or the session is no longer valid.

Media typeapplication/problem+json
object
code

A stable refusal code the client branches on, where the status alone is not enough: owner_role_manage_required and self_lockout on the role editor’s 409s; revision_mismatch (a stale If-Match) and document_bound_elsewhere (the document backs another record) on an expense claim’s 409s.

string
detail
string
instance
string
status
required
integer
title
required
string
type
required
string

Example generated

{
"code": "example",
"detail": "example",
"instance": "example",
"status": 1,
"title": "example",
"type": "example"
}

The caller does not hold the permission this operation requires.

Media typeapplication/problem+json
object
code

A stable refusal code the client branches on, where the status alone is not enough: owner_role_manage_required and self_lockout on the role editor’s 409s; revision_mismatch (a stale If-Match) and document_bound_elsewhere (the document backs another record) on an expense claim’s 409s.

string
detail
string
instance
string
status
required
integer
title
required
string
type
required
string

Example generated

{
"code": "example",
"detail": "example",
"instance": "example",
"status": 1,
"title": "example",
"type": "example"
}

The Idempotency-Key was already used for a different request (idempotency_key_reused), or the same request is still being processed (idempotency_in_progress; retry after Retry-After), or the records are in another state (conflict).

Media typeapplication/problem+json
object
code

A stable refusal code the client branches on, where the status alone is not enough: owner_role_manage_required and self_lockout on the role editor’s 409s; revision_mismatch (a stale If-Match) and document_bound_elsewhere (the document backs another record) on an expense claim’s 409s.

string
detail
string
instance
string
status
required
integer
title
required
string
type
required
string

Example generated

{
"code": "example",
"detail": "example",
"instance": "example",
"status": 1,
"title": "example",
"type": "example"
}

The request is well-formed but refused by an AR rule (validation), or the Idempotency-Key header is missing or too long (idempotency_key_required).

Media typeapplication/problem+json
object
code

A stable refusal code the client branches on, where the status alone is not enough: owner_role_manage_required and self_lockout on the role editor’s 409s; revision_mismatch (a stale If-Match) and document_bound_elsewhere (the document backs another record) on an expense claim’s 409s.

string
detail
string
instance
string
status
required
integer
title
required
string
type
required
string

Example generated

{
"code": "example",
"detail": "example",
"instance": "example",
"status": 1,
"title": "example",
"type": "example"
}

A rate limit was reached: per API key, per organization across its keys, or per source address for repeated failed key authentication. Retry after the number of seconds in Retry-After. Every answer on a key carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset.

Media typeapplication/problem+json
object
code

A stable refusal code the client branches on, where the status alone is not enough: owner_role_manage_required and self_lockout on the role editor’s 409s; revision_mismatch (a stale If-Match) and document_bound_elsewhere (the document backs another record) on an expense claim’s 409s.

string
detail
string
instance
string
status
required
integer
title
required
string
type
required
string

Example generated

{
"code": "example",
"detail": "example",
"instance": "example",
"status": 1,
"title": "example",
"type": "example"
}
Retry-After
integer

Seconds until a retry may succeed.