# Invoice Status and Notices

https://dev.wisecp.com/es/invoice-status-and-notices

The five endpoints for an invoice's status, its client details and the notices sent.

## Overview

These five endpoints run the **life** of an invoice once issued. They change its status, correct the client details, send a notice, formalise it and remind.

The status change is the **heaviest** thing here. Marking an invoice paid opens an income entry, gives it a paid-invoice number and sets the linked services moving; refunding winds that back and can order a refund through the payment module.

Three of the endpoints **mail the client**: the notice, the reminder and, when its file is there, formalising. Calling them from a script reaches real people.

## Reference

### Changing the Status

put/api/v1/admin/invoices/{id}/status

`Invoices/UpdateInvoiceStatus` admin it has side effects

Changes an invoice's status and carries out what that status brings.

Body 5

statusstringreqThe new status: `paid`, `unpaid`, `refund` or `cancelled`.

payment_methodstringThe payment method. On a paid invoice, sending this alone changes the method.

refund_methodstringHow the refund happens. It can go back through the payment module.

cancel_servicesboolCancels the services on the invoice as well. It works on refund and cancel.

notifyboolTells the client.

Response fields data

dataobjectThe invoice as it now stands. Same shape as the detail endpoint.

Errors 5

not_found404No such invoice.

invalid_status422The status is not recognised.

same_status422The invoice already stands there.

blocked_by_gate422A hook refused the change.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X PUT 'https://panel.example.com/api/v1/admin/invoices/1212/status' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"status":"paid","payment_method":"Balance","notify":true}'
```

```javascript
const res = await fetch(`https://panel.example.com/api/v1/admin/invoices/${id}/status`, {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    status: 'paid',
    payment_method: 'Balance',
    notify: true,
  }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/invoices/' . $id . '/status');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'status'         => 'paid',
        'payment_method' => 'Balance',
        'notify'         => true,
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// Marking it paid OPENS AN INCOME ENTRY, gives a number and sets the services moving.
Api::Invoices()->UpdateInvoiceStatus([
    'id'     => $id,
    'status' => 'paid',
    'notify' => true,
]);
```

### Correcting the Client Details

patch/api/v1/admin/invoices/{id}/client-details

`Invoices/UpdateInvoiceClientDetails` admin this invoice only

Corrects the client and address details frozen onto an invoice.

Body 10

kindstringWhether the client is a person or a company. On a person the company name is cleared.

first_namestringThe first name. The full name is built from it.

last_namestringThe last name.

emailstringThe e-mail address.

phonestringThe phone.

identitystringThe identity or tax number.

company_namestringThe company name. It applies to a company.

tax_numberstringThe tax number.

tax_officestringThe tax office.

addressobjectThe address: street, country, state, city and postcode. State and city are resolved from an id when given as a number and stored as written when given as text.

Response fields data

dataobjectThe invoice as it now stands. Same shape as the detail endpoint.

Errors 2

not_found404No such invoice.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X PATCH 'https://panel.example.com/api/v1/admin/invoices/1212/client-details' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"kind":"corporate","company_name":"Ornek A.S.","tax_number":"0000000000"}'
```

```javascript
const res = await fetch(`https://panel.example.com/api/v1/admin/invoices/${id}/client-details`, {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    kind: 'corporate',
    company_name: 'Example Inc.',
    tax_number: '000000000',
    address: { detail: '123 Market Street', country_id: 840, zipcode: '94105' },
  }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/invoices/' . $id . '/client-details');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PATCH',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'kind'         => 'corporate',
        'company_name' => 'Example Inc.',
        'tax_number'   => '000000000',
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// This endpoint DOES NOT TOUCH the live client; it corrects the copy on this invoice.
Api::Invoices()->UpdateInvoiceClientDetails([
    'id'           => $id,
    'company_name' => 'Example Inc.',
]);
```

### Sending a Notice

post/api/v1/admin/invoices/{id}/notifications

`Invoices/SendInvoiceNotification` admin a real e-mail goes out

Sends the client the invoice notice template you pick.

Body 1

templatestringreqThe key of the template to send. It has to be one of the invoice notices and switched on.

Response fields data — 3

sentboolWhether the send ran.

templatestringThe template sent.

invoice_idintThe invoice id.

Errors 4

not_found404No such invoice.

template_required422No template was given.

invalid_template422The template is not recognised, or it is switched off.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X POST 'https://panel.example.com/api/v1/admin/invoices/1231/notifications' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"template":"invoice-created"}'
```

```javascript
const res = await fetch(`https://panel.example.com/api/v1/admin/invoices/${id}/notifications`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ template: 'invoice-created' }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/invoices/' . $id . '/notifications');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['template' => 'invoice-created']),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// A switched-off template gives a 422; the list on screen does not mark which are on.
Api::Invoices()->SendInvoiceNotification([
    'id'       => $id,
    'template' => 'invoice-created',
]);
```

### Formalising an Invoice

post/api/v1/admin/invoices/{id}/formalize

`Invoices/FormalizeInvoice` admin once only

Turns an invoice into a formal one.

Body 1

notifyboolTells the client. It goes out when a formalisation file is there.

Response fields data

dataobjectThe invoice as it now stands. Same shape as the detail endpoint.

Errors 4

not_found404No such invoice.

already_formalized422The invoice is already formal.

blocked_by_gate422A hook refused it.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X POST 'https://panel.example.com/api/v1/admin/invoices/1231/formalize' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"notify":false}'
```

```javascript
const res = await fetch(`https://panel.example.com/api/v1/admin/invoices/${id}/formalize`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ notify: false }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/invoices/' . $id . '/formalize');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['notify' => false]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// A second call gives a 422; in a batch script read the invoice's state first.
$inv = Api::Invoices()->GetInvoice(['id' => $id])['data'];
if (! $inv['formalized']) Api::Invoices()->FormalizeInvoice(['id' => $id]);
```

### Sending a Reminder

post/api/v1/admin/invoices/{id}/remind

`Invoices/RemindInvoice` admin

Sends the client a reminder for an unpaid invoice.

Body —

——No body is needed, send an empty one. The invoice comes from the path, and the notification sent is `invoice-reminder`; there is no field to change it with.

Response fields data — 2

remindedboolWhether the send ran.

invoice_idintThe invoice id.

Errors 2

not_found404No such invoice.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X POST 'https://panel.example.com/api/v1/admin/invoices/1231/remind' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res = await fetch(`https://panel.example.com/api/v1/admin/invoices/${id}/remind`, {
  method: 'POST',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/invoices/' . $id . '/remind');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// The call counts NO ATTEMPTS; it will remind the same invoice again and again.
Api::Invoices()->RemindInvoice(['id' => $id]);
```

## Pitfalls

> **A status change never travels alone**
> 
> Marking an invoice paid **opens an income entry**. It also gives the invoice a paid number and sets the linked services moving. Refunding winds all of that back, unwinds the metered rows and can order a refund through the payment module. Do not try this on a real client's invoice.

> **Moving to the same status is an error**
> 
> When the invoice already stands there, the call is **refused**. The one exception is changing the payment method on a paid invoice, where the status holds and only the method is written. A script that syncs statuses should read the current one first.

> **The client correction belongs to the invoice**
> 
> This endpoint corrects the **frozen copy** on the invoice and leaves the live client record alone. A wrong address may need fixing in both places. Correct it here for the document already issued, and on the client for the ones to come. A correction here does not reach other invoices either.

> **Formalising happens once**
> 
> Formalising an invoice that is already formal **gives an error**. In a batch script that stops the loop at the first one, so read each invoice's state first. A hook can refuse it as well, because on some installations the act has a counterpart in the books.

> **Reminders are not counted**
> 
> The reminder endpoint **keeps no count** of how often it was called, and calling it twice sends the same client two mails. A script that walks the overdue invoices should keep on its own side which invoice was reminded and when. Otherwise every run warns everyone again.

## Related Articles

- [Managing Invoices](https://dev.wisecp.com/en/managing-invoices)
- [Invoice Items and Payments](https://dev.wisecp.com/en/invoice-items-and-payments)
- [Cash Records](https://dev.wisecp.com/en/cash-records)
