Payment receipts
Introduction
What this guide covers
This guide describes how to keep Unimicro up to date about payments. When a payment changes (it is approved, paid or rejected) or when money arrives in a bank account, you report it to us with a payment receipt. This page explains:
- what a payment receipt is and when to use it,
- how to report status changes for payments we sent out (remittances),
- how to report money that has been received (receivables),
- the fields, status codes and examples you need, and
- how to make us apply the receipt (the mandatory processing step).
You don't need any banking knowledge. Banking terms are explained where they appear.
Who it is for
This guide is for developers building an integration with Unimicro that handles payments. Typical examples are:
- a payment provider or bank connector that sends our payments to the bank and returns their status,
- a bank statement integration that reads transactions from the bank and reports incoming money,
- a third-party application that needs to show or update payment status in a company's accounts.
It does not cover how to create payments or send them to the bank. It starts at the point where something has happened to a payment and you want to tell us.
Before you start
- You need access to the Unimicro API and a company to work with.
- For status updates on payments we sent out, you need the
EndToEndIDwe gave each payment. Without it, we cannot match your update to a payment.
Overview
A payment receipt tells us that something has happened with a payment. It is used in two situations:
- Remittances (outgoing payments). Money the company pays to others, such as supplier invoices. You report status changes: approved, sent to the bank, paid, rejected, and so on.
- Receivables (incoming payments). Money the company receives, such as customers paying invoices. You report money that has arrived in the bank account, and we register it as incoming payments.
A receipt holds the latest known information about one or more payments. Each payment or booking is a line on the receipt.
Reporting takes two steps:
- Create the receipt (
POST). - Process the receipt (
PUTwithaction=process). This step is mandatory. Nothing is applied until you do this.
Remittance or receivable? The EndToEndID decides
The receipt API has no "direction" field. We decide from EndToEndID.
Remittance (outgoing payment):
EndToEndIDis required. It is the ID we gave the payment when it was sent. Return it unchanged.- It started in our system. We created the payment and sent it out.
- We update the status of the existing payment.
Stateis used. It sets the new status.
Receivable (incoming payment):
EndToEndIDmust be null or empty, on the line and on every detail.- It started outside our system. The money arrived on its own and we don't know about it yet.
- We create new payments, one per detail.
Stateis not used. Received money is always registered as paid.
A receivable must never have an EndToEndID. If you set one, the line is treated as an update to a remittance and no new payments are created. If no payment with that ID exists, the line is silently ignored.The EndToEndID has the format E:<text>:<number>, for example E:abc:555. Values that do not match this format are ignored.
Amounts are normally positive
Banks normally report amounts as positive numbers, whether money left or arrived in the account. Don't use the sign to show the direction. Use EndToEndID for that (see above).
- Remittance: positive
BookedAmount. - Receivable: positive
ValueAmounton each detail.
Negative amounts are credit lines
A negative amount is still allowed, and it means a credit line, for example a credit note or a refund. Credit lines work for both directions:
- Remittances: a credit line that was part of a payment batch, reported with its
EndToEndID. - Receivables: a detail with a negative
ValueAmount.
Keep the sign consistent with the payment. If the payment you are reporting on is a credit (negative), a BookedAmount you send must be negative too. A positive amount will be seen as a difference and the stored amount is adjusted.
Step 1: Create a receipt
POST https://{baseurl}/api/biz/paymentreceipts
Receipt fields
ReceiptDateTime(datetime, UTC): When the information was produced, e.g.2024-01-01T12:34:56Z. Defaults to the time of the request.FileID(number): Optional. The ID of a file you have already uploaded to us, such as the original message you received from the bank or payment provider (JSON or XML). It is not needed for the receipt to work, but you can use it to keep the original as the source of truth, so an update can always be traced back to what was received.State(status code): Optional. Only used together withPaymentBatchID, see the "Updating a whole batch" example.StateChangeReason(text): Optional. Reason for the status. Only used together withPaymentBatchID.PaymentBatchID(number): Optional. Only used together withState.Lines(list): The payments this receipt is about.
Line fields
EndToEndID(text, max 35): Identifies a remittance. Must be null or empty for receivables.State(status code): The new status of a remittance, see "Status codes" below. Not used for receivables.StateChangeReason(text, max 255): Explains the status, e.g. why a payment was rejected.RegisteredDateTime(datetime, UTC): When this line was produced. Defaults to the time of the request.AccountServiceReference(text, max 35): The bank's or payment provider's reference for the payment. Items with the same value post to the same journal entry, unless their date or account differs.BookedAmount(number): The amount booked on the bank account, in the currency of the account (e.g. NOK). For receivables this is the total of the line.BookedAmountCurrency(number): The amount in the payment's own currency. Same asBookedAmountfor domestic payments.CurrencyCode(text, 3 characters): Currency of the payment, e.g.NOK,EUR.ExchangeRate(number): Exchange rate used. Use1when no conversion took place.BankCharges(number): Total bank charges for the line, in the currency of the account.BookedDate(date): The date the money was booked, e.g.2024-08-29.ExternalIdentifier(text, max 255): Your own unique ID for incoming money (e.g. a bank transaction ID). Strongly recommended for receivables, see "Avoiding duplicates".Details(list): Required for receivables. One entry per individual payment.
Detail fields (receivables)
ValueAmount(number): Amount of this payment. Same currency as the line. Currencies cannot be mixed.BankCharges(number): Charges for this payment, always in the currency of the account.CurrencyCode(text, 3 characters): Currency code.DebtorNameandDebtorAccountNumber(text): Who paid: name and account number or IBAN.CreditorNameandCreditorAccountNumber(text): Who received the money. The account number must match a bank account registered on the company.RemittanceType(number): WhatRemittanceReferencecontains, see below.RemittanceReference(text, max 400): The payment reference given by the payer.AdditionalRemittanceInformation(text, max 255): Extra text from the payer.BankTransactionCode(text, max 14): The bank's transaction code in the formatDomain-Family-SubFamily.BankTransactionProprietary(text, max 255): The bank's own transaction type, if provided.EndToEndID(text): Must be null or empty for receivables.
RemittanceType values
0=UnstructuredReference: the reference is free text or a description.10=StructuredCommunicationReference: the reference is a KID number.20=CommercialInvoice: the reference is an invoice number.
Status codes
0=Ignore: Not relevant to us. The line is skipped. Use this for status codes you don't need to report.10=ReceivedByAgent: The payment provider has collected the payment and is processing it.20=AwaitingApproval: Waiting for the first approval.21=AwaitAdditionalApproval: Waiting for further approvals, when more than one is required.22=PreApproved: Approved, but not yet sent to the bank.25=AwaitingBankStatus: Waiting to be transferred to the bank.30=AwaitingSettlement: At the bank, waiting to be paid out.40=Settled: Paid.50=Rejected: Refused by the payment provider or the bank. Put the reason inStateChangeReason.51=Cancelled: Cancelled by the user or the bank. A reason can be given inStateChangeReason.
A status that is not a valid next step for a payment (for example going from Settled back to AwaitingApproval) is skipped without an error. If one receipt contains several lines for the same payment, the line with the highest status is used.
Receivables: lines and details
For a receivable, a line is one booking on the bank account. A line can contain several details. Each detail is one actual payment, and each becomes a separate incoming payment in our system.
- Line = what the bank booked. Amounts and charges are the total (the group amount).
- Detail = one payer's payment inside that booking.
This is common when a customer or a bank collects many payments and the bank books them as one sum (for example an OCR/KID collection). One amount lands in the account, but it consists of many individual payments.
For example, one line of 1,000.00 booked on the account:
- Detail 1: 250.00 from Ola Nordmann (KID 01000001234562)
- Detail 2: 450.00 from Kari Nordmann (KID 01000005678902)
- Detail 3: 300.00 from Nordlys Bygg AS (invoice 2024-117)
It does not have to be like this. In most cases a line contains exactly one detail: one booking, one payment.
Every receivable line must have at least one detail. The details are what we register as payments. A receivable line without details cannot be processed. Nothing is registered, and the receipt may fail.
For the numbers to be consistent:
- The
ValueAmountof all details should add up to the total amount of the line. BankChargeson the line is the sum of all charges. If the details carry less charge in total than the line, the rest is added to the first payment.- All details on one line have the same currency as the line.
- Set
ExternalIdentifieron the line (see below).
Avoiding duplicates
For receivables, set ExternalIdentifier to a unique ID from your system, such as the bank's transaction ID. If a line with the same ExternalIdentifier was already processed in another receipt, it is skipped. This makes it safe to send again after a timeout.
Examples
Remittances: status and booking update
{
"ReceiptDateTime": "2024-01-01T12:34:56Z",
"FileID": 1,
"Lines": [
{
"EndToEndID": "E:abc:111",
"State": "Cancelled",
"StateChangeReason": "Invalid debtor account"
},
{
"EndToEndID": "E:abc:333",
"State": "AwaitingSettlement"
},
{
"EndToEndID": "E:abc:555",
"State": "Settled",
"AccountServiceReference": "ABC",
"BookedAmount": 450.00,
"BookedAmountCurrency": 450.00,
"BankCharges": 0.00,
"BookedDate": "2024-01-01",
"ExchangeRate": 1.0
}
]
}
Receivable 1: one booking, one payment (most common)
{
"ReceiptDateTime": "2024-08-29T08:00:00Z",
"Lines": [
{
"ExternalIdentifier": "bank-tx-10001",
"BookedAmount": 250.00,
"BookedAmountCurrency": 250.00,
"BankCharges": 0.00,
"BookedDate": "2024-08-29",
"CurrencyCode": "NOK",
"ExchangeRate": 1.0,
"Details": [
{
"ValueAmount": 250.00,
"BankCharges": 0.00,
"CreditorName": "Fjordheim Regnskap AS",
"CreditorAccountNumber": "15032080119",
"DebtorName": "Ola Nordmann",
"DebtorAccountNumber": "86011117947",
"RemittanceReference": "01000001234562",
"RemittanceType": 10
}
]
}
]
}
Receivable 2: one booking, several payments (OCR sum)
The bank booked 1,000.00 as one amount. It consists of three payments, each with its own reference. The line holds the total, and the three details become three payments.
{
"ReceiptDateTime": "2024-08-29T08:00:00Z",
"Lines": [
{
"ExternalIdentifier": "bank-tx-10002",
"BookedAmount": 1000.00,
"BookedAmountCurrency": 1000.00,
"BankCharges": 0.00,
"BookedDate": "2024-08-29",
"CurrencyCode": "NOK",
"ExchangeRate": 1.0,
"Details": [
{
"ValueAmount": 250.00,
"CreditorAccountNumber": "15032080119",
"DebtorName": "Ola Nordmann",
"RemittanceReference": "01000001234562",
"RemittanceType": 10
},
{
"ValueAmount": 450.00,
"CreditorAccountNumber": "15032080119",
"DebtorName": "Kari Nordmann",
"RemittanceReference": "01000005678902",
"RemittanceType": 10
},
{
"ValueAmount": 300.00,
"CreditorAccountNumber": "15032080119",
"DebtorName": "Nordlys Bygg AS",
"RemittanceReference": "2024-117",
"RemittanceType": 20
}
]
}
]
}
Receivable 3: several separate bookings in one receipt
A receipt can contain several lines, one per booking. Each line has its own details.
{
"ReceiptDateTime": "2024-08-29T08:00:00Z",
"Lines": [
{
"ExternalIdentifier": "bank-tx-10003",
"BookedAmount": 250.0,
"BookedAmountCurrency": 250.0,
"BookedDate": "2024-08-29",
"CurrencyCode": "NOK",
"Details": [
{
"ValueAmount": 250.0,
"CreditorAccountNumber": "15032080119",
"DebtorName": "Ola Nordmann",
"RemittanceReference": "01000001234562",
"RemittanceType": 10
}
]
},
{
"ExternalIdentifier": "bank-tx-10004",
"BookedAmount": 750.0,
"BookedAmountCurrency": 750.0,
"BookedDate": "2024-08-29",
"CurrencyCode": "NOK",
"Details": [
{
"ValueAmount": 450.0,
"CreditorAccountNumber": "15032080119",
"DebtorName": "Kari Nordmann",
"RemittanceReference": "01000005678902",
"RemittanceType": 10
},
{
"ValueAmount": 300.0,
"CreditorAccountNumber": "15032080119",
"DebtorName": "Nordlys Bygg AS",
"RemittanceReference": "2024-117",
"RemittanceType": 20
}
]
}
]
}
Receivable 4: with a credit detail
The line total is 700.00: a payment of 1,000.00 and a credit of -300.00.
{
"ReceiptDateTime": "2024-08-29T08:00:00Z",
"Lines": [
{
"ExternalIdentifier": "bank-tx-10005",
"BookedAmount": 700.0,
"BookedAmountCurrency": 700.0,
"BookedDate": "2024-08-29",
"CurrencyCode": "NOK",
"Details": [
{
"ValueAmount": 1000.0,
"CreditorAccountNumber": "15032080119",
"DebtorName": "Nordlys Bygg AS",
"RemittanceReference": "2024-117",
"RemittanceType": 20
},
{
"ValueAmount": -300.0,
"CreditorAccountNumber": "15032080119",
"DebtorName": "Nordlys Bygg AS",
"RemittanceReference": "Kreditnota 2024-9",
"RemittanceType": 0
}
]
}
]
}
Receivable 5: unknown sender
Sometimes the bank doesn't tell us who paid, for example with cash deposits or when the payer's details are hidden. In that case, leave out DebtorName and DebtorAccountNumber. We register the incoming payment without a sender. Keep the reference if there is one, as it helps to match the payment to an invoice later.
{
"ReceiptDateTime": "2024-08-29T08:00:00Z",
"Lines": [
{
"ExternalIdentifier": "bank-tx-10006",
"BookedAmount": 500.00,
"BookedAmountCurrency": 500.00,
"BankCharges": 0.00,
"BookedDate": "2024-08-29",
"CurrencyCode": "NOK",
"ExchangeRate": 1.0,
"Details": [
{
"ValueAmount": 500.00,
"CreditorName": "Fjordheim Regnskap AS",
"CreditorAccountNumber": "15032080119",
"RemittanceReference": "Innbetaling faktura 2024-131",
"RemittanceType": 0
}
]
}
]
}
Updating a whole batch
If every payment in a payment batch gets the same new status, you don't have to list each payment. Send PaymentBatchID and State and leave out Lines. We create a line for every payment in the batch ourselves. The status of the batch itself is updated immediately when you create the receipt.
{
"ReceiptDateTime": "2024-01-01T12:34:56Z",
"PaymentBatchID": 42,
"State": "AwaitingApproval"
}
Response
200 OK with the saved receipt. Keep the ID for the next step.
{ "ID": 1}
Step 2: Process the receipt (mandatory)
This step is mandatory. Creating a receipt (Step 1) only stores it. Nothing happens until you process it: no payment statuses are updated and no incoming payments are registered. If you skip this step, the receipt is simply stored and ignored.
PUT https://{baseurl}/api/biz/paymentreceipts/{id}?action=process&acceptjob=true
This applies the changes: remittances get their new status, paid payments are updated with amounts and dates, and received money is registered as incoming payments.
Always use the background job, unless a user is waiting
Use acceptjob=true for all updates that do not need an immediate result. This is the normal way to process a receipt.Only use immediate processing (without acceptjob) when you have built a payment flow where a user is waiting on screen and must see the latest status of the payment right away. Otherwise the user would be looking at outdated data.
Booking payments is not a real-time action. Registering received money (receivables) and updating paid remittances from bank statements should always be sent as a background job, even when a user started the synchronization.
Background job (recommended)
- How: add
acceptjob=trueto the URL, or send the headerAcceptJob: true. - Use it almost always: bank statement imports, booking of received money, status updates from your system, and any receipt with many lines.
- The call returns at once and the work is queued.
Immediate (exceptions only)
- How: remove
&acceptjob=truefrom the URL, so it becomesPUT https://{baseurl}/api/biz/paymentreceipts/{id}?action=process. - Use it only in a payment flow where a user needs direct feedback.
- It is processed during the request and returns
200 OKwith an empty body when done. Large receipts can make the request slow or time out.
Immediate processing is what happens if you leave out acceptjob=true, so don't remove it from the URL above unless you have a reason to.
Background job response:
{
"JobId": "12345",
"Status": 0,
"HasError": false,
"Completed": false,
"ProgressUrl": "https://{baseurl}/api/jobinfo/12345"
}
HTTP status codes:
202 Accepted: The job is queued or running. This is the normal response. PollProgressUrlto follow it.200 OK: The job has already finished successfully.400 Bad Request: The job finished with an error. SeeHasErrorand the job info.
Paid remittances are bookkept automatically in the background about a minute after processing.
Final notes
Send data in bulk
Do not create a receipt for each individual payment. Collect many payments and send them together in one receipt, with one line per payment or booking, and then process that receipt once.
- Every receipt means two requests (create and process) and one background job on our side. Thousands of tiny receipts create a lot of overhead and a long queue. They will not make updates arrive faster.
- One receipt with many lines is processed far more efficiently than the same lines spread over many receipts.
You are free to split the data into smaller chunks when it makes sense for you. Good reasons to do so are:
- Very large imports: several receipts of a reasonable size, for example a few thousand lines each, so a single failure does not block everything. For incoming payments, a natural way to split is per bank account or per booking date. Only do this when there is a lot of data. For normal volumes, one receipt is enough.
- Different sources: keeping data from separate bank statements or files apart, so each receipt can be traced to its source with
FileID.
Avoid splitting down to a single payment per receipt, unless a user in a payment flow is waiting for that one payment (see Step 2).
Quick checklist
- Create the receipt, then process it. Processing is mandatory.
- Use
acceptjob=trueunless a user is waiting for the result. - Remittances need an
EndToEndID. Receivables must have it null or empty. - Every receivable line needs at least one detail.
- Send many lines per receipt. Do not create one receipt per payment.
- Set
ExternalIdentifieron receivable lines so a resend is safe.