Skip to content

API reference

Customer invoices

Customer invoices: drafts, issuing, e-mail, credit, payments and PDF. An issued invoice never changes.

List customer invoices

GET /invoices listInvoices

Customer invoices and credit invoices, drafts included, with rows and payments.

Scope

invoices:view

Parameters

  • limit integer query

    Page size, 1–200.

    Default: 50 · minimum 1 · maximum 200

  • cursor string query

    Opaque cursor from meta.next_cursor of the previous page.

    at most 2000 characters

  • updated_since string (date-time) query

    Only records whose updated_at is strictly later than this ISO 8601 time. Lists are ordered by updated_at, then id, so a sync stores the updated_at of the last record it has seen and passes it next time, walking all pages with `cursor`.

    Example: 2026-03-01T00:00:00+01:00

  • status string query

    DRAFT, ISSUED (unpaid), PAID or CREDITED.

    Values: DRAFT, ISSUED, PAID, CREDITED

  • kind string query

    INVOICE or CREDIT.

    Values: INVOICE, CREDIT

  • customer_id integer query

    Only this customer.

  • date_from string (date) query

    From this date (YYYY-MM-DD), inclusive.

  • date_to string (date) query

    Up to this date (YYYY-MM-DD), inclusive.

Responses

200 OK – A page of invoices.

application/jsonobject

  • data array<Invoice> required
    34 fields · each item
    • id string (uuid)
    • number integer nullable

      Gapless invoice number, null while a draft.

    • kind string

      Values: INVOICE, CREDIT

    • status string

      Open enum.

      Values: DRAFT, ISSUED, PAID, CREDITED

    • credits_invoice_id string (uuid) nullable
    • customer_id integer
    • customer object

      The customer as on the invoice (frozen when issued). Never a personal number.

      6 fields
      • number integer nullable
      • name string nullable
      • org_number string nullable
      • vat_number string nullable
      • email string nullable
      • address object
        5 fields
        • line1 string nullable
        • line2 string nullable
        • postal_code string nullable
        • city string nullable
        • country string nullable
    • invoice_date string (date)
    • due_date string (date)
    • delivery_date string (date) nullable
    • your_reference string nullable
    • our_reference string nullable
    • notes string nullable
    • reverse_charge boolean
    • foreign_sale string nullable
    • tax_reduction string nullable

      ROT or RUT.

    • tax_reduction_ore integer
    • property_designation string nullable
    • currency string
    • net_ore integer
    • vat_ore integer
    • rounding_ore integer

      Öresavrundning to whole kronor.

    • total_ore integer
    • paid_ore integer
    • remaining_ore integer
    • ocr string nullable
    • voucher_id string (uuid) nullable
    • issued_at string (date-time) nullable
    • sent_at string (date-time) nullable
    • sent_to string nullable
    • rows array<InvoiceRow>
      10 fields · each item
      • article string nullable
      • description string
      • quantity string

        Decimal string, up to three decimals; negative on credit invoices.

      • unit string
      • unit_price_ore integer
      • discount_bp integer

        Discount in basis points (1000 is 10 %).

      • vat_rate integer
      • account integer nullable
      • net_ore integer
      • labour boolean

        Labour cost (ROT/RUT).

    • payments array<InvoicePayment>
      9 fields · each item
      • id integer
      • invoice_id string (uuid)
      • paid_on string (date)
      • amount_ore integer
      • currency string
      • account integer nullable

        Bank account the money came in on.

      • voucher_id string (uuid)
      • created_at string (date-time)
      • updated_at string (date-time)
    • created_at string (date-time)
    • updated_at string (date-time)
  • meta ListMeta required
    3 fields
    • limit integer required
    • next_cursor string required nullable

      Opaque; pass as `cursor` for the next page. null on the last page.

    • has_more boolean required

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

401 Unauthorized – Missing, invalid, expired or revoked token or API key. Also returned when the person behind the credential has left the company (an OAuth grant is then revoked for good).

All error codes · application/problem+json

  • unauthenticatedNo valid credential

    Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, WWW-Authenticate

403 Forbidden – The credential may not do this: a scope is missing, the granting person no longer has the permission, the address is not allowed, the company is archived (read-only) or no longer allows the app.

All error codes · application/problem+json

  • insufficient_scopeScope missing or permission lost

    Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.

  • forbiddenThe action refuses (for example changing a posted voucher)

    Behörighet saknas för det här.

  • ip_not_allowedOutside the IP allowlist

    Företaget tillåter inte anrop från den här adressen.

  • company_archivedWrite to an archived company

    Företaget är arkiverat och kan bara läsas.

  • app_not_allowedThe company no longer allows the app

    Företaget tillåter inte längre den här appen.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

404 Not Found – Not found. Also the answer for another company's ids (existence is never revealed) and for every call while NONOX Connect is turned off for the company.

All error codes · application/problem+json

  • not_foundUnknown id, other company's id, or module off

    Det du söker finns inte.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

429 Too Many Requests – Rate limit exceeded (per credential, per company or per address). Wait Retry-After seconds.

All error codes · application/problem+json

  • rate_limitedOver the limit

    För många anrop. Försök igen om 23 sekunder.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Retry-After

Code samples

curl
curl "https://nonox.app/api/v1/invoices?limit=50&updated_since=2026-03-01T00%3A00%3A00%2B01%3A00" \
  -H "Authorization: Bearer $NONOX_TOKEN" \
  -H "Accept: application/json"
PHP (Laravel)
use Illuminate\Support\Facades\Http;

$response = Http::withToken(config('services.nonox.token'))
    ->acceptJson()
    ->get('https://nonox.app/api/v1/invoices', [
        'limit' => 50,
        'updated_since' => '2026-03-01T00:00:00+01:00',
    ]);

$response->throw();

$data = $response->json('data');
PHP (Guzzle)
$client = new \GuzzleHttp\Client(['timeout' => 30]);

$response = $client->request('GET', 'https://nonox.app/api/v1/invoices', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('NONOX_TOKEN'),
        'Accept' => 'application/json',
    ],
    'query' => [
        'limit' => 50,
        'updated_since' => '2026-03-01T00:00:00+01:00',
    ],
]);

$data = json_decode((string) $response->getBody(), true, flags: JSON_THROW_ON_ERROR)['data'];
JavaScript
const url = new URL('https://nonox.app/api/v1/invoices');
url.searchParams.set('limit', '50');
url.searchParams.set('updated_since', '2026-03-01T00:00:00+01:00');

const response = await fetch(url, {
  headers: {
    Authorization: `Bearer ${process.env.NONOX_TOKEN}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const problem = await response.json();
  throw new Error(`${problem.code}: ${problem.detail}`);
}

const { data } = await response.json();
Python
import os
import requests

response = requests.get(
    "https://nonox.app/api/v1/invoices",
    headers={
        "Authorization": f"Bearer {os.environ['NONOX_TOKEN']}",
        "Accept": "application/json",
    },
    params={
        "limit": 50,
        "updated_since": "2026-03-01T00:00:00+01:00",
    },
    timeout=30,
)
response.raise_for_status()

data = response.json()["data"]

Responses · 200

application/json
{
  "data": [
    {
      "id": "5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54",
      "number": 1042,
      "kind": "INVOICE",
      "status": "PAID",
      "credits_invoice_id": null,
      "customer_id": 18,
      "customer": {
        "number": 1004,
        "name": "Kund Exempel AB",
        "org_number": "559900-4560",
        "vat_number": "SE559900456001",
        "email": "faktura@kund.example.se",
        "address": {
          "line1": "Kundvägen 5",
          "line2": null,
          "postal_code": "222 33",
          "city": "Exempelby",
          "country": "SE"
        }
      },
      "invoice_date": "2026-03-02",
      "due_date": "2026-04-01",
      "delivery_date": null,
      "your_reference": "Anna Exempel",
      "our_reference": null,
      "notes": null,
      "reverse_charge": false,
      "foreign_sale": null,
      "tax_reduction": null,
      "tax_reduction_ore": 0,
      "property_designation": null,
      "currency": "SEK",
      "net_ore": 190000,
      "vat_ore": 47500,
      "rounding_ore": 0,
      "total_ore": 237500,
      "paid_ore": 237500,
      "remaining_ore": 0,
      "ocr": "104257",
      "voucher_id": "1d2e3f4a-5b6c-4d7e-8f9a-0b1c2d3e4f5a",
      "issued_at": "2026-03-02T10:45:12+01:00",
      "sent_at": "2026-03-02T10:45:12+01:00",
      "sent_to": "faktura@kund.example.se",
      "rows": [
        {
          "article": "TIM",
          "description": "Konsulttimme",
          "quantity": "2",
          "unit": "h",
          "unit_price_ore": 95000,
          "discount_bp": 0,
          "vat_rate": 2500,
          "account": 3001,
          "net_ore": 190000,
          "labour": false
        }
      ],
      "payments": [
        {
          "id": 88,
          "invoice_id": "5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54",
          "paid_on": "2026-03-28",
          "amount_ore": 237500,
          "currency": "SEK",
          "account": 1930,
          "voucher_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
          "created_at": "2026-03-28T09:12:00+01:00",
          "updated_at": "2026-03-28T09:12:00+01:00"
        }
      ],
      "created_at": "2026-03-02T10:45:12+01:00",
      "updated_at": "2026-03-28T09:12:00+01:00"
    }
  ],
  "meta": {
    "limit": 50,
    "next_cursor": null,
    "has_more": false
  }
}

Error

4011 example
No valid credential
{
  "type": "urn:nonox:problem:unauthenticated",
  "title": "Unauthorized",
  "status": 401,
  "code": "unauthenticated",
  "detail": "Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4035 examples
Scope missing or permission lost
{
  "type": "urn:nonox:problem:insufficient_scope",
  "title": "Forbidden",
  "status": 403,
  "code": "insufficient_scope",
  "detail": "Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17",
  "required_scopes": [
    "vouchers:post"
  ]
}
The action refuses (for example changing a posted voucher)
{
  "type": "urn:nonox:problem:forbidden",
  "title": "Forbidden",
  "status": 403,
  "code": "forbidden",
  "detail": "Behörighet saknas för det här.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Outside the IP allowlist
{
  "type": "urn:nonox:problem:ip_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "ip_not_allowed",
  "detail": "Företaget tillåter inte anrop från den här adressen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Write to an archived company
{
  "type": "urn:nonox:problem:company_archived",
  "title": "Forbidden",
  "status": 403,
  "code": "company_archived",
  "detail": "Företaget är arkiverat och kan bara läsas.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
The company no longer allows the app
{
  "type": "urn:nonox:problem:app_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "app_not_allowed",
  "detail": "Företaget tillåter inte längre den här appen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4041 example
Unknown id, other company's id, or module off
{
  "type": "urn:nonox:problem:not_found",
  "title": "Not Found",
  "status": 404,
  "code": "not_found",
  "detail": "Det du söker finns inte.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4291 example
Over the limit
{
  "type": "urn:nonox:problem:rate_limited",
  "title": "Too Many Requests",
  "status": 429,
  "code": "rate_limited",
  "detail": "För många anrop. Försök igen om 23 sekunder.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}

Create a draft invoice

POST /invoices createInvoice

Creates a draft. Nothing is booked and no number is taken until it is issued. The due date follows the customer's payment terms unless given; totals, VAT and öresavrundning are calculated. Same Action as the app (SaveDraftInvoice).

Scope

invoices:create

Parameters

  • Idempotency-Key string header required

    Required on every POST. A unique value per intended operation (a UUID v4 is ideal), 1–255 visible ASCII characters. Kept 24 hours per credential: the same key with the same request returns the stored response (Idempotent-Replayed: true); with a different request 422 idempotency_key_reused; while the first is still running 409. Server errors (5xx) are not stored, so retry with the same key.

    at least 1 characters · at most 255 characters · Example: 3f6c1b7e-2d4a-4e8b-9c0d-5a1b2c3d4e5f

Request body

application/jsonInvoiceInput required

  • customer_id integer required
  • invoice_date string (date) required
  • due_date string (date) nullable
  • delivery_date string (date) nullable
  • your_reference string nullable
  • our_reference string nullable
  • notes string nullable

    at most 2000 characters

  • reverse_charge boolean nullable
  • foreign_sale string nullable
  • tax_reduction string nullable

    Values: ROT, RUT

  • property_designation string nullable
  • rows array<InvoiceRowInput> required
    9 fields · each item
    • article string nullable

      Article number. Its name, price and VAT rate are used for fields left out.

    • description string

      at most 255 characters

    • quantity integer | string

      An integer, or a decimal string such as "1.5". Default 1.

      2 fields
      • One of integer
      • One of string
    • unit string

      at most 10 characters

    • unit_price_ore integer
    • discount_bp integer

      minimum 0 · maximum 10000

    • vat_rate integer

      Values: 2500, 1200, 600, 0

    • account integer nullable
    • labour boolean

Responses

201 Created – The draft.

application/jsonobject

  • data Invoice required
    34 fields
    • id string (uuid)
    • number integer nullable

      Gapless invoice number, null while a draft.

    • kind string

      Values: INVOICE, CREDIT

    • status string

      Open enum.

      Values: DRAFT, ISSUED, PAID, CREDITED

    • credits_invoice_id string (uuid) nullable
    • customer_id integer
    • customer object

      The customer as on the invoice (frozen when issued). Never a personal number.

      6 fields
      • number integer nullable
      • name string nullable
      • org_number string nullable
      • vat_number string nullable
      • email string nullable
      • address object
        5 fields
        • line1 string nullable
        • line2 string nullable
        • postal_code string nullable
        • city string nullable
        • country string nullable
    • invoice_date string (date)
    • due_date string (date)
    • delivery_date string (date) nullable
    • your_reference string nullable
    • our_reference string nullable
    • notes string nullable
    • reverse_charge boolean
    • foreign_sale string nullable
    • tax_reduction string nullable

      ROT or RUT.

    • tax_reduction_ore integer
    • property_designation string nullable
    • currency string
    • net_ore integer
    • vat_ore integer
    • rounding_ore integer

      Öresavrundning to whole kronor.

    • total_ore integer
    • paid_ore integer
    • remaining_ore integer
    • ocr string nullable
    • voucher_id string (uuid) nullable
    • issued_at string (date-time) nullable
    • sent_at string (date-time) nullable
    • sent_to string nullable
    • rows array<InvoiceRow>
      10 fields · each item
      • article string nullable
      • description string
      • quantity string

        Decimal string, up to three decimals; negative on credit invoices.

      • unit string
      • unit_price_ore integer
      • discount_bp integer

        Discount in basis points (1000 is 10 %).

      • vat_rate integer
      • account integer nullable
      • net_ore integer
      • labour boolean

        Labour cost (ROT/RUT).

    • payments array<InvoicePayment>
      9 fields · each item
      • id integer
      • invoice_id string (uuid)
      • paid_on string (date)
      • amount_ore integer
      • currency string
      • account integer nullable

        Bank account the money came in on.

      • voucher_id string (uuid)
      • created_at string (date-time)
      • updated_at string (date-time)
    • created_at string (date-time)
    • updated_at string (date-time)

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Location, Idempotent-Replayed

400 Bad Request – Bad request: missing or invalid Idempotency-Key, or a body that is not a JSON object.

All error codes · application/problem+json

  • idempotency_key_requiredNo Idempotency-Key on a POST

    Skicka en unik Idempotency-Key (till exempel ett UUID) med varje POST, så att ett nytt försök aldrig bokför två gånger.

  • idempotency_key_invalidIdempotency-Key too long or not visible ASCII

    Idempotency-Key ska vara 1–255 synliga ASCII-tecken.

  • invalid_jsonMalformed JSON

    Kroppen är inte giltig JSON (ett objekt).

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

401 Unauthorized – Missing, invalid, expired or revoked token or API key. Also returned when the person behind the credential has left the company (an OAuth grant is then revoked for good).

All error codes · application/problem+json

  • unauthenticatedNo valid credential

    Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, WWW-Authenticate

403 Forbidden – The credential may not do this: a scope is missing, the granting person no longer has the permission, the address is not allowed, the company is archived (read-only) or no longer allows the app.

All error codes · application/problem+json

  • insufficient_scopeScope missing or permission lost

    Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.

  • forbiddenThe action refuses (for example changing a posted voucher)

    Behörighet saknas för det här.

  • ip_not_allowedOutside the IP allowlist

    Företaget tillåter inte anrop från den här adressen.

  • company_archivedWrite to an archived company

    Företaget är arkiverat och kan bara läsas.

  • app_not_allowedThe company no longer allows the app

    Företaget tillåter inte längre den här appen.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

404 Not Found – Not found. Also the answer for another company's ids (existence is never revealed) and for every call while NONOX Connect is turned off for the company.

All error codes · application/problem+json

  • not_foundUnknown id, other company's id, or module off

    Det du söker finns inte.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

409 Conflict – A request with the same Idempotency-Key is still running.

All error codes · application/problem+json

  • idempotency_in_progressSame key, first request not finished

    En begäran med samma Idempotency-Key pågår. Vänta och försök igen.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Retry-After

415 Unsupported Media Type – The body is not application/json (or multipart/form-data where a file is accepted).

All error codes · application/problem+json

  • unsupported_media_typeWrong Content-Type

    Skicka JSON (application/json).

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

422 Unprocessable Content – Validation failed, or the Idempotency-Key was already used for a different request.

All error codes · application/problem+json

  • validation_failedField errors

    Uppgifterna kunde inte godtas. Se errors.

  • idempotency_key_reusedSame key, different body

    Idempotency-Key har redan använts för en annan begäran. Använd en ny nyckel för en ny begäran.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

429 Too Many Requests – Rate limit exceeded (per credential, per company or per address). Wait Retry-After seconds.

All error codes · application/problem+json

  • rate_limitedOver the limit

    För många anrop. Försök igen om 23 sekunder.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Retry-After

Code samples

curl
curl -X POST "https://nonox.app/api/v1/invoices" \
  -H "Authorization: Bearer $NONOX_TOKEN" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "customer_id": 18,
  "invoice_date": "2026-03-02",
  "your_reference": "Anna Exempel",
  "rows": [
    {
      "article": "TIM",
      "quantity": 2
    },
    {
      "description": "Resa",
      "quantity": "1.5",
      "unit_price_ore": 20000,
      "vat_rate": 2500,
      "discount_bp": 1000
    }
  ]
}'
PHP (Laravel)
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;

$response = Http::withToken(config('services.nonox.token'))
    ->acceptJson()
    ->withHeaders(['Idempotency-Key' => (string) Str::uuid()])
    ->post('https://nonox.app/api/v1/invoices', [
        'customer_id' => 18,
        'invoice_date' => '2026-03-02',
        'your_reference' => 'Anna Exempel',
        'rows' => [
            [
                'article' => 'TIM',
                'quantity' => 2,
            ],
            [
                'description' => 'Resa',
                'quantity' => '1.5',
                'unit_price_ore' => 20000,
                'vat_rate' => 2500,
                'discount_bp' => 1000,
            ],
        ],
    ]);

$response->throw();

$data = $response->json('data');
PHP (Guzzle)
$client = new \GuzzleHttp\Client(['timeout' => 30]);

$response = $client->request('POST', 'https://nonox.app/api/v1/invoices', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('NONOX_TOKEN'),
        'Accept' => 'application/json',
        'Idempotency-Key' => bin2hex(random_bytes(16)),
    ],
    'json' => [
        'customer_id' => 18,
        'invoice_date' => '2026-03-02',
        'your_reference' => 'Anna Exempel',
        'rows' => [
            [
                'article' => 'TIM',
                'quantity' => 2,
            ],
            [
                'description' => 'Resa',
                'quantity' => '1.5',
                'unit_price_ore' => 20000,
                'vat_rate' => 2500,
                'discount_bp' => 1000,
            ],
        ],
    ],
]);

$data = json_decode((string) $response->getBody(), true, flags: JSON_THROW_ON_ERROR)['data'];
JavaScript
const response = await fetch('https://nonox.app/api/v1/invoices', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.NONOX_TOKEN}`,
    Accept: 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "customer_id": 18,
    "invoice_date": "2026-03-02",
    "your_reference": "Anna Exempel",
    "rows": [
      {
        "article": "TIM",
        "quantity": 2
      },
      {
        "description": "Resa",
        "quantity": "1.5",
        "unit_price_ore": 20000,
        "vat_rate": 2500,
        "discount_bp": 1000
      }
    ]
  }),
});

if (!response.ok) {
  const problem = await response.json();
  throw new Error(`${problem.code}: ${problem.detail}`);
}

const { data } = await response.json();
Python
import os
import uuid
import requests

response = requests.post(
    "https://nonox.app/api/v1/invoices",
    headers={
        "Authorization": f"Bearer {os.environ['NONOX_TOKEN']}",
        "Accept": "application/json",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "customer_id": 18,
        "invoice_date": "2026-03-02",
        "your_reference": "Anna Exempel",
        "rows": [
            {
                "article": "TIM",
                "quantity": 2,
            },
            {
                "description": "Resa",
                "quantity": "1.5",
                "unit_price_ore": 20000,
                "vat_rate": 2500,
                "discount_bp": 1000,
            },
        ],
    },
    timeout=30,
)
response.raise_for_status()

data = response.json()["data"]

Responses · 201

application/json
{
  "data": {
    "id": "5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54",
    "number": 1042,
    "kind": "INVOICE",
    "status": "PAID",
    "credits_invoice_id": null,
    "customer_id": 18,
    "customer": {
      "number": 1004,
      "name": "Kund Exempel AB",
      "org_number": "559900-4560",
      "vat_number": "SE559900456001",
      "email": "faktura@kund.example.se",
      "address": {
        "line1": "Kundvägen 5",
        "line2": null,
        "postal_code": "222 33",
        "city": "Exempelby",
        "country": "SE"
      }
    },
    "invoice_date": "2026-03-02",
    "due_date": "2026-04-01",
    "delivery_date": null,
    "your_reference": "Anna Exempel",
    "our_reference": null,
    "notes": null,
    "reverse_charge": false,
    "foreign_sale": null,
    "tax_reduction": null,
    "tax_reduction_ore": 0,
    "property_designation": null,
    "currency": "SEK",
    "net_ore": 190000,
    "vat_ore": 47500,
    "rounding_ore": 0,
    "total_ore": 237500,
    "paid_ore": 237500,
    "remaining_ore": 0,
    "ocr": "104257",
    "voucher_id": "1d2e3f4a-5b6c-4d7e-8f9a-0b1c2d3e4f5a",
    "issued_at": "2026-03-02T10:45:12+01:00",
    "sent_at": "2026-03-02T10:45:12+01:00",
    "sent_to": "faktura@kund.example.se",
    "rows": [
      {
        "article": "TIM",
        "description": "Konsulttimme",
        "quantity": "2",
        "unit": "h",
        "unit_price_ore": 95000,
        "discount_bp": 0,
        "vat_rate": 2500,
        "account": 3001,
        "net_ore": 190000,
        "labour": false
      }
    ],
    "payments": [
      {
        "id": 88,
        "invoice_id": "5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54",
        "paid_on": "2026-03-28",
        "amount_ore": 237500,
        "currency": "SEK",
        "account": 1930,
        "voucher_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
        "created_at": "2026-03-28T09:12:00+01:00",
        "updated_at": "2026-03-28T09:12:00+01:00"
      }
    ],
    "created_at": "2026-03-02T10:45:12+01:00",
    "updated_at": "2026-03-28T09:12:00+01:00"
  }
}

Error

4003 examples
No Idempotency-Key on a POST
{
  "type": "urn:nonox:problem:idempotency_key_required",
  "title": "Bad Request",
  "status": 400,
  "code": "idempotency_key_required",
  "detail": "Skicka en unik Idempotency-Key (till exempel ett UUID) med varje POST, så att ett nytt försök aldrig bokför två gånger.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Idempotency-Key too long or not visible ASCII
{
  "type": "urn:nonox:problem:idempotency_key_invalid",
  "title": "Bad Request",
  "status": 400,
  "code": "idempotency_key_invalid",
  "detail": "Idempotency-Key ska vara 1–255 synliga ASCII-tecken.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Malformed JSON
{
  "type": "urn:nonox:problem:invalid_json",
  "title": "Bad Request",
  "status": 400,
  "code": "invalid_json",
  "detail": "Kroppen är inte giltig JSON (ett objekt).",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4011 example
No valid credential
{
  "type": "urn:nonox:problem:unauthenticated",
  "title": "Unauthorized",
  "status": 401,
  "code": "unauthenticated",
  "detail": "Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4035 examples
Scope missing or permission lost
{
  "type": "urn:nonox:problem:insufficient_scope",
  "title": "Forbidden",
  "status": 403,
  "code": "insufficient_scope",
  "detail": "Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17",
  "required_scopes": [
    "vouchers:post"
  ]
}
The action refuses (for example changing a posted voucher)
{
  "type": "urn:nonox:problem:forbidden",
  "title": "Forbidden",
  "status": 403,
  "code": "forbidden",
  "detail": "Behörighet saknas för det här.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Outside the IP allowlist
{
  "type": "urn:nonox:problem:ip_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "ip_not_allowed",
  "detail": "Företaget tillåter inte anrop från den här adressen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Write to an archived company
{
  "type": "urn:nonox:problem:company_archived",
  "title": "Forbidden",
  "status": 403,
  "code": "company_archived",
  "detail": "Företaget är arkiverat och kan bara läsas.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
The company no longer allows the app
{
  "type": "urn:nonox:problem:app_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "app_not_allowed",
  "detail": "Företaget tillåter inte längre den här appen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4041 example
Unknown id, other company's id, or module off
{
  "type": "urn:nonox:problem:not_found",
  "title": "Not Found",
  "status": 404,
  "code": "not_found",
  "detail": "Det du söker finns inte.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4091 example
Same key, first request not finished
{
  "type": "urn:nonox:problem:idempotency_in_progress",
  "title": "Conflict",
  "status": 409,
  "code": "idempotency_in_progress",
  "detail": "En begäran med samma Idempotency-Key pågår. Vänta och försök igen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4151 example
Wrong Content-Type
{
  "type": "urn:nonox:problem:unsupported_media_type",
  "title": "Unsupported Media Type",
  "status": 415,
  "code": "unsupported_media_type",
  "detail": "Skicka JSON (application/json).",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4222 examples
Field errors
{
  "type": "urn:nonox:problem:validation_failed",
  "title": "Unprocessable Content",
  "status": 422,
  "code": "validation_failed",
  "detail": "Uppgifterna kunde inte godtas. Se errors.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17",
  "errors": {
    "rows": [
      "Verifikationen balanserar inte: debet och kredit skiljer sig åt."
    ],
    "voucher_date": [
      "Det finns inget räkenskapsår som omfattar 2031-01-01."
    ]
  }
}
Same key, different body
{
  "type": "urn:nonox:problem:idempotency_key_reused",
  "title": "Unprocessable Content",
  "status": 422,
  "code": "idempotency_key_reused",
  "detail": "Idempotency-Key har redan använts för en annan begäran. Använd en ny nyckel för en ny begäran.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4291 example
Over the limit
{
  "type": "urn:nonox:problem:rate_limited",
  "title": "Too Many Requests",
  "status": 429,
  "code": "rate_limited",
  "detail": "För många anrop. Försök igen om 23 sekunder.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}

Get a customer invoice

GET /invoices/{invoice} getInvoice

One invoice with rows and payments. Never a personal number.

Scope

invoices:view

Parameters

  • invoice string (uuid) path required

    Invoice id (UUID, not the invoice number).

    Example: 5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54

Responses

200 OK – The invoice.

application/jsonobject

  • data Invoice required
    34 fields
    • id string (uuid)
    • number integer nullable

      Gapless invoice number, null while a draft.

    • kind string

      Values: INVOICE, CREDIT

    • status string

      Open enum.

      Values: DRAFT, ISSUED, PAID, CREDITED

    • credits_invoice_id string (uuid) nullable
    • customer_id integer
    • customer object

      The customer as on the invoice (frozen when issued). Never a personal number.

      6 fields
      • number integer nullable
      • name string nullable
      • org_number string nullable
      • vat_number string nullable
      • email string nullable
      • address object
        5 fields
        • line1 string nullable
        • line2 string nullable
        • postal_code string nullable
        • city string nullable
        • country string nullable
    • invoice_date string (date)
    • due_date string (date)
    • delivery_date string (date) nullable
    • your_reference string nullable
    • our_reference string nullable
    • notes string nullable
    • reverse_charge boolean
    • foreign_sale string nullable
    • tax_reduction string nullable

      ROT or RUT.

    • tax_reduction_ore integer
    • property_designation string nullable
    • currency string
    • net_ore integer
    • vat_ore integer
    • rounding_ore integer

      Öresavrundning to whole kronor.

    • total_ore integer
    • paid_ore integer
    • remaining_ore integer
    • ocr string nullable
    • voucher_id string (uuid) nullable
    • issued_at string (date-time) nullable
    • sent_at string (date-time) nullable
    • sent_to string nullable
    • rows array<InvoiceRow>
      10 fields · each item
      • article string nullable
      • description string
      • quantity string

        Decimal string, up to three decimals; negative on credit invoices.

      • unit string
      • unit_price_ore integer
      • discount_bp integer

        Discount in basis points (1000 is 10 %).

      • vat_rate integer
      • account integer nullable
      • net_ore integer
      • labour boolean

        Labour cost (ROT/RUT).

    • payments array<InvoicePayment>
      9 fields · each item
      • id integer
      • invoice_id string (uuid)
      • paid_on string (date)
      • amount_ore integer
      • currency string
      • account integer nullable

        Bank account the money came in on.

      • voucher_id string (uuid)
      • created_at string (date-time)
      • updated_at string (date-time)
    • created_at string (date-time)
    • updated_at string (date-time)

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

401 Unauthorized – Missing, invalid, expired or revoked token or API key. Also returned when the person behind the credential has left the company (an OAuth grant is then revoked for good).

All error codes · application/problem+json

  • unauthenticatedNo valid credential

    Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, WWW-Authenticate

403 Forbidden – The credential may not do this: a scope is missing, the granting person no longer has the permission, the address is not allowed, the company is archived (read-only) or no longer allows the app.

All error codes · application/problem+json

  • insufficient_scopeScope missing or permission lost

    Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.

  • forbiddenThe action refuses (for example changing a posted voucher)

    Behörighet saknas för det här.

  • ip_not_allowedOutside the IP allowlist

    Företaget tillåter inte anrop från den här adressen.

  • company_archivedWrite to an archived company

    Företaget är arkiverat och kan bara läsas.

  • app_not_allowedThe company no longer allows the app

    Företaget tillåter inte längre den här appen.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

404 Not Found – Not found. Also the answer for another company's ids (existence is never revealed) and for every call while NONOX Connect is turned off for the company.

All error codes · application/problem+json

  • not_foundUnknown id, other company's id, or module off

    Det du söker finns inte.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

429 Too Many Requests – Rate limit exceeded (per credential, per company or per address). Wait Retry-After seconds.

All error codes · application/problem+json

  • rate_limitedOver the limit

    För många anrop. Försök igen om 23 sekunder.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Retry-After

Code samples

curl
curl "https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54" \
  -H "Authorization: Bearer $NONOX_TOKEN" \
  -H "Accept: application/json"
PHP (Laravel)
use Illuminate\Support\Facades\Http;

$response = Http::withToken(config('services.nonox.token'))
    ->acceptJson()
    ->get('https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54');

$response->throw();

$data = $response->json('data');
PHP (Guzzle)
$client = new \GuzzleHttp\Client(['timeout' => 30]);

$response = $client->request('GET', 'https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('NONOX_TOKEN'),
        'Accept' => 'application/json',
    ],
]);

$data = json_decode((string) $response->getBody(), true, flags: JSON_THROW_ON_ERROR)['data'];
JavaScript
const response = await fetch('https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54', {
  headers: {
    Authorization: `Bearer ${process.env.NONOX_TOKEN}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const problem = await response.json();
  throw new Error(`${problem.code}: ${problem.detail}`);
}

const { data } = await response.json();
Python
import os
import requests

response = requests.get(
    "https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54",
    headers={
        "Authorization": f"Bearer {os.environ['NONOX_TOKEN']}",
        "Accept": "application/json",
    },
    timeout=30,
)
response.raise_for_status()

data = response.json()["data"]

Responses · 200

application/json
{
  "data": {
    "id": "5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54",
    "number": 1042,
    "kind": "INVOICE",
    "status": "PAID",
    "credits_invoice_id": null,
    "customer_id": 18,
    "customer": {
      "number": 1004,
      "name": "Kund Exempel AB",
      "org_number": "559900-4560",
      "vat_number": "SE559900456001",
      "email": "faktura@kund.example.se",
      "address": {
        "line1": "Kundvägen 5",
        "line2": null,
        "postal_code": "222 33",
        "city": "Exempelby",
        "country": "SE"
      }
    },
    "invoice_date": "2026-03-02",
    "due_date": "2026-04-01",
    "delivery_date": null,
    "your_reference": "Anna Exempel",
    "our_reference": null,
    "notes": null,
    "reverse_charge": false,
    "foreign_sale": null,
    "tax_reduction": null,
    "tax_reduction_ore": 0,
    "property_designation": null,
    "currency": "SEK",
    "net_ore": 190000,
    "vat_ore": 47500,
    "rounding_ore": 0,
    "total_ore": 237500,
    "paid_ore": 237500,
    "remaining_ore": 0,
    "ocr": "104257",
    "voucher_id": "1d2e3f4a-5b6c-4d7e-8f9a-0b1c2d3e4f5a",
    "issued_at": "2026-03-02T10:45:12+01:00",
    "sent_at": "2026-03-02T10:45:12+01:00",
    "sent_to": "faktura@kund.example.se",
    "rows": [
      {
        "article": "TIM",
        "description": "Konsulttimme",
        "quantity": "2",
        "unit": "h",
        "unit_price_ore": 95000,
        "discount_bp": 0,
        "vat_rate": 2500,
        "account": 3001,
        "net_ore": 190000,
        "labour": false
      }
    ],
    "payments": [
      {
        "id": 88,
        "invoice_id": "5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54",
        "paid_on": "2026-03-28",
        "amount_ore": 237500,
        "currency": "SEK",
        "account": 1930,
        "voucher_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
        "created_at": "2026-03-28T09:12:00+01:00",
        "updated_at": "2026-03-28T09:12:00+01:00"
      }
    ],
    "created_at": "2026-03-02T10:45:12+01:00",
    "updated_at": "2026-03-28T09:12:00+01:00"
  }
}

Error

4011 example
No valid credential
{
  "type": "urn:nonox:problem:unauthenticated",
  "title": "Unauthorized",
  "status": 401,
  "code": "unauthenticated",
  "detail": "Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4035 examples
Scope missing or permission lost
{
  "type": "urn:nonox:problem:insufficient_scope",
  "title": "Forbidden",
  "status": 403,
  "code": "insufficient_scope",
  "detail": "Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17",
  "required_scopes": [
    "vouchers:post"
  ]
}
The action refuses (for example changing a posted voucher)
{
  "type": "urn:nonox:problem:forbidden",
  "title": "Forbidden",
  "status": 403,
  "code": "forbidden",
  "detail": "Behörighet saknas för det här.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Outside the IP allowlist
{
  "type": "urn:nonox:problem:ip_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "ip_not_allowed",
  "detail": "Företaget tillåter inte anrop från den här adressen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Write to an archived company
{
  "type": "urn:nonox:problem:company_archived",
  "title": "Forbidden",
  "status": 403,
  "code": "company_archived",
  "detail": "Företaget är arkiverat och kan bara läsas.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
The company no longer allows the app
{
  "type": "urn:nonox:problem:app_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "app_not_allowed",
  "detail": "Företaget tillåter inte längre den här appen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4041 example
Unknown id, other company's id, or module off
{
  "type": "urn:nonox:problem:not_found",
  "title": "Not Found",
  "status": 404,
  "code": "not_found",
  "detail": "Det du söker finns inte.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4291 example
Over the limit
{
  "type": "urn:nonox:problem:rate_limited",
  "title": "Too Many Requests",
  "status": 429,
  "code": "rate_limited",
  "detail": "För många anrop. Försök igen om 23 sekunder.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}

Change a draft invoice

PATCH /invoices/{invoice} updateInvoice

Changes a draft; an issued invoice answers 403 and never changes.

Scope

invoices:create

Parameters

  • invoice string (uuid) path required

    Invoice id (UUID, not the invoice number).

    Example: 5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54

Request body

application/jsonInvoicePatch required

Only the fields sent are changed; `rows`, when sent, replaces all rows.

  • customer_id integer
  • invoice_date string (date)
  • due_date string (date) nullable
  • delivery_date string (date) nullable
  • your_reference string nullable
  • our_reference string nullable
  • notes string nullable

    at most 2000 characters

  • reverse_charge boolean nullable
  • foreign_sale string nullable
  • tax_reduction string nullable

    Values: ROT, RUT

  • property_designation string nullable
  • rows array<InvoiceRowInput>
    9 fields · each item
    • article string nullable

      Article number. Its name, price and VAT rate are used for fields left out.

    • description string

      at most 255 characters

    • quantity integer | string

      An integer, or a decimal string such as "1.5". Default 1.

      2 fields
      • One of integer
      • One of string
    • unit string

      at most 10 characters

    • unit_price_ore integer
    • discount_bp integer

      minimum 0 · maximum 10000

    • vat_rate integer

      Values: 2500, 1200, 600, 0

    • account integer nullable
    • labour boolean

Responses

200 OK – The draft.

application/jsonobject

  • data Invoice required
    34 fields
    • id string (uuid)
    • number integer nullable

      Gapless invoice number, null while a draft.

    • kind string

      Values: INVOICE, CREDIT

    • status string

      Open enum.

      Values: DRAFT, ISSUED, PAID, CREDITED

    • credits_invoice_id string (uuid) nullable
    • customer_id integer
    • customer object

      The customer as on the invoice (frozen when issued). Never a personal number.

      6 fields
      • number integer nullable
      • name string nullable
      • org_number string nullable
      • vat_number string nullable
      • email string nullable
      • address object
        5 fields
        • line1 string nullable
        • line2 string nullable
        • postal_code string nullable
        • city string nullable
        • country string nullable
    • invoice_date string (date)
    • due_date string (date)
    • delivery_date string (date) nullable
    • your_reference string nullable
    • our_reference string nullable
    • notes string nullable
    • reverse_charge boolean
    • foreign_sale string nullable
    • tax_reduction string nullable

      ROT or RUT.

    • tax_reduction_ore integer
    • property_designation string nullable
    • currency string
    • net_ore integer
    • vat_ore integer
    • rounding_ore integer

      Öresavrundning to whole kronor.

    • total_ore integer
    • paid_ore integer
    • remaining_ore integer
    • ocr string nullable
    • voucher_id string (uuid) nullable
    • issued_at string (date-time) nullable
    • sent_at string (date-time) nullable
    • sent_to string nullable
    • rows array<InvoiceRow>
      10 fields · each item
      • article string nullable
      • description string
      • quantity string

        Decimal string, up to three decimals; negative on credit invoices.

      • unit string
      • unit_price_ore integer
      • discount_bp integer

        Discount in basis points (1000 is 10 %).

      • vat_rate integer
      • account integer nullable
      • net_ore integer
      • labour boolean

        Labour cost (ROT/RUT).

    • payments array<InvoicePayment>
      9 fields · each item
      • id integer
      • invoice_id string (uuid)
      • paid_on string (date)
      • amount_ore integer
      • currency string
      • account integer nullable

        Bank account the money came in on.

      • voucher_id string (uuid)
      • created_at string (date-time)
      • updated_at string (date-time)
    • created_at string (date-time)
    • updated_at string (date-time)

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

401 Unauthorized – Missing, invalid, expired or revoked token or API key. Also returned when the person behind the credential has left the company (an OAuth grant is then revoked for good).

All error codes · application/problem+json

  • unauthenticatedNo valid credential

    Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, WWW-Authenticate

403 Forbidden – The credential may not do this: a scope is missing, the granting person no longer has the permission, the address is not allowed, the company is archived (read-only) or no longer allows the app.

All error codes · application/problem+json

  • insufficient_scopeScope missing or permission lost

    Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.

  • forbiddenThe action refuses (for example changing a posted voucher)

    Behörighet saknas för det här.

  • ip_not_allowedOutside the IP allowlist

    Företaget tillåter inte anrop från den här adressen.

  • company_archivedWrite to an archived company

    Företaget är arkiverat och kan bara läsas.

  • app_not_allowedThe company no longer allows the app

    Företaget tillåter inte längre den här appen.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

404 Not Found – Not found. Also the answer for another company's ids (existence is never revealed) and for every call while NONOX Connect is turned off for the company.

All error codes · application/problem+json

  • not_foundUnknown id, other company's id, or module off

    Det du söker finns inte.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

415 Unsupported Media Type – The body is not application/json (or multipart/form-data where a file is accepted).

All error codes · application/problem+json

  • unsupported_media_typeWrong Content-Type

    Skicka JSON (application/json).

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

422 Unprocessable Content – Validation failed, or the Idempotency-Key was already used for a different request.

All error codes · application/problem+json

  • validation_failedField errors

    Uppgifterna kunde inte godtas. Se errors.

  • idempotency_key_reusedSame key, different body

    Idempotency-Key har redan använts för en annan begäran. Använd en ny nyckel för en ny begäran.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

429 Too Many Requests – Rate limit exceeded (per credential, per company or per address). Wait Retry-After seconds.

All error codes · application/problem+json

  • rate_limitedOver the limit

    För många anrop. Försök igen om 23 sekunder.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Retry-After

Code samples

curl
curl -X PATCH "https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54" \
  -H "Authorization: Bearer $NONOX_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "your_reference": "Anna Exempel"
}'
PHP (Laravel)
use Illuminate\Support\Facades\Http;

$response = Http::withToken(config('services.nonox.token'))
    ->acceptJson()
    ->patch('https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54', [
        'your_reference' => 'Anna Exempel',
    ]);

$response->throw();

$data = $response->json('data');
PHP (Guzzle)
$client = new \GuzzleHttp\Client(['timeout' => 30]);

$response = $client->request('PATCH', 'https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('NONOX_TOKEN'),
        'Accept' => 'application/json',
    ],
    'json' => [
        'your_reference' => 'Anna Exempel',
    ],
]);

$data = json_decode((string) $response->getBody(), true, flags: JSON_THROW_ON_ERROR)['data'];
JavaScript
const response = await fetch('https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.NONOX_TOKEN}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "your_reference": "Anna Exempel"
  }),
});

if (!response.ok) {
  const problem = await response.json();
  throw new Error(`${problem.code}: ${problem.detail}`);
}

const { data } = await response.json();
Python
import os
import requests

response = requests.patch(
    "https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54",
    headers={
        "Authorization": f"Bearer {os.environ['NONOX_TOKEN']}",
        "Accept": "application/json",
    },
    json={
        "your_reference": "Anna Exempel",
    },
    timeout=30,
)
response.raise_for_status()

data = response.json()["data"]

Responses · 200

application/json
{
  "data": {
    "id": "5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54",
    "number": 1042,
    "kind": "INVOICE",
    "status": "PAID",
    "credits_invoice_id": null,
    "customer_id": 18,
    "customer": {
      "number": 1004,
      "name": "Kund Exempel AB",
      "org_number": "559900-4560",
      "vat_number": "SE559900456001",
      "email": "faktura@kund.example.se",
      "address": {
        "line1": "Kundvägen 5",
        "line2": null,
        "postal_code": "222 33",
        "city": "Exempelby",
        "country": "SE"
      }
    },
    "invoice_date": "2026-03-02",
    "due_date": "2026-04-01",
    "delivery_date": null,
    "your_reference": "Anna Exempel",
    "our_reference": null,
    "notes": null,
    "reverse_charge": false,
    "foreign_sale": null,
    "tax_reduction": null,
    "tax_reduction_ore": 0,
    "property_designation": null,
    "currency": "SEK",
    "net_ore": 190000,
    "vat_ore": 47500,
    "rounding_ore": 0,
    "total_ore": 237500,
    "paid_ore": 237500,
    "remaining_ore": 0,
    "ocr": "104257",
    "voucher_id": "1d2e3f4a-5b6c-4d7e-8f9a-0b1c2d3e4f5a",
    "issued_at": "2026-03-02T10:45:12+01:00",
    "sent_at": "2026-03-02T10:45:12+01:00",
    "sent_to": "faktura@kund.example.se",
    "rows": [
      {
        "article": "TIM",
        "description": "Konsulttimme",
        "quantity": "2",
        "unit": "h",
        "unit_price_ore": 95000,
        "discount_bp": 0,
        "vat_rate": 2500,
        "account": 3001,
        "net_ore": 190000,
        "labour": false
      }
    ],
    "payments": [
      {
        "id": 88,
        "invoice_id": "5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54",
        "paid_on": "2026-03-28",
        "amount_ore": 237500,
        "currency": "SEK",
        "account": 1930,
        "voucher_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
        "created_at": "2026-03-28T09:12:00+01:00",
        "updated_at": "2026-03-28T09:12:00+01:00"
      }
    ],
    "created_at": "2026-03-02T10:45:12+01:00",
    "updated_at": "2026-03-28T09:12:00+01:00"
  }
}

Error

4011 example
No valid credential
{
  "type": "urn:nonox:problem:unauthenticated",
  "title": "Unauthorized",
  "status": 401,
  "code": "unauthenticated",
  "detail": "Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4035 examples
Scope missing or permission lost
{
  "type": "urn:nonox:problem:insufficient_scope",
  "title": "Forbidden",
  "status": 403,
  "code": "insufficient_scope",
  "detail": "Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17",
  "required_scopes": [
    "vouchers:post"
  ]
}
The action refuses (for example changing a posted voucher)
{
  "type": "urn:nonox:problem:forbidden",
  "title": "Forbidden",
  "status": 403,
  "code": "forbidden",
  "detail": "Behörighet saknas för det här.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Outside the IP allowlist
{
  "type": "urn:nonox:problem:ip_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "ip_not_allowed",
  "detail": "Företaget tillåter inte anrop från den här adressen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Write to an archived company
{
  "type": "urn:nonox:problem:company_archived",
  "title": "Forbidden",
  "status": 403,
  "code": "company_archived",
  "detail": "Företaget är arkiverat och kan bara läsas.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
The company no longer allows the app
{
  "type": "urn:nonox:problem:app_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "app_not_allowed",
  "detail": "Företaget tillåter inte längre den här appen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4041 example
Unknown id, other company's id, or module off
{
  "type": "urn:nonox:problem:not_found",
  "title": "Not Found",
  "status": 404,
  "code": "not_found",
  "detail": "Det du söker finns inte.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4151 example
Wrong Content-Type
{
  "type": "urn:nonox:problem:unsupported_media_type",
  "title": "Unsupported Media Type",
  "status": 415,
  "code": "unsupported_media_type",
  "detail": "Skicka JSON (application/json).",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4222 examples
Field errors
{
  "type": "urn:nonox:problem:validation_failed",
  "title": "Unprocessable Content",
  "status": 422,
  "code": "validation_failed",
  "detail": "Uppgifterna kunde inte godtas. Se errors.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17",
  "errors": {
    "rows": [
      "Verifikationen balanserar inte: debet och kredit skiljer sig åt."
    ],
    "voucher_date": [
      "Det finns inget räkenskapsår som omfattar 2031-01-01."
    ]
  }
}
Same key, different body
{
  "type": "urn:nonox:problem:idempotency_key_reused",
  "title": "Unprocessable Content",
  "status": 422,
  "code": "idempotency_key_reused",
  "detail": "Idempotency-Key har redan använts för en annan begäran. Använd en ny nyckel för en ny begäran.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4291 example
Over the limit
{
  "type": "urn:nonox:problem:rate_limited",
  "title": "Too Many Requests",
  "status": 429,
  "code": "rate_limited",
  "detail": "För många anrop. Försök igen om 23 sekunder.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}

Issue (book) a draft invoice

POST /invoices/{invoice}/issue issueInvoice

Makes the draft an invoice: the next gapless invoice number, an OCR reference, the customer frozen, and under fakturametoden a voucher in series B. Irreversible; a mistake is credited. Does not e-mail it (see /send). Books a voucher as the person behind the credential, so the credential also needs vouchers:create and vouchers:post. Same Action as the app (IssueInvoice).

Scope

invoices:send + vouchers:create + vouchers:post

Parameters

  • invoice string (uuid) path required

    Invoice id (UUID, not the invoice number).

    Example: 5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54

  • Idempotency-Key string header required

    Required on every POST. A unique value per intended operation (a UUID v4 is ideal), 1–255 visible ASCII characters. Kept 24 hours per credential: the same key with the same request returns the stored response (Idempotent-Replayed: true); with a different request 422 idempotency_key_reused; while the first is still running 409. Server errors (5xx) are not stored, so retry with the same key.

    at least 1 characters · at most 255 characters · Example: 3f6c1b7e-2d4a-4e8b-9c0d-5a1b2c3d4e5f

Responses

200 OK – The issued invoice.

application/jsonobject

  • data Invoice required
    34 fields
    • id string (uuid)
    • number integer nullable

      Gapless invoice number, null while a draft.

    • kind string

      Values: INVOICE, CREDIT

    • status string

      Open enum.

      Values: DRAFT, ISSUED, PAID, CREDITED

    • credits_invoice_id string (uuid) nullable
    • customer_id integer
    • customer object

      The customer as on the invoice (frozen when issued). Never a personal number.

      6 fields
      • number integer nullable
      • name string nullable
      • org_number string nullable
      • vat_number string nullable
      • email string nullable
      • address object
        5 fields
        • line1 string nullable
        • line2 string nullable
        • postal_code string nullable
        • city string nullable
        • country string nullable
    • invoice_date string (date)
    • due_date string (date)
    • delivery_date string (date) nullable
    • your_reference string nullable
    • our_reference string nullable
    • notes string nullable
    • reverse_charge boolean
    • foreign_sale string nullable
    • tax_reduction string nullable

      ROT or RUT.

    • tax_reduction_ore integer
    • property_designation string nullable
    • currency string
    • net_ore integer
    • vat_ore integer
    • rounding_ore integer

      Öresavrundning to whole kronor.

    • total_ore integer
    • paid_ore integer
    • remaining_ore integer
    • ocr string nullable
    • voucher_id string (uuid) nullable
    • issued_at string (date-time) nullable
    • sent_at string (date-time) nullable
    • sent_to string nullable
    • rows array<InvoiceRow>
      10 fields · each item
      • article string nullable
      • description string
      • quantity string

        Decimal string, up to three decimals; negative on credit invoices.

      • unit string
      • unit_price_ore integer
      • discount_bp integer

        Discount in basis points (1000 is 10 %).

      • vat_rate integer
      • account integer nullable
      • net_ore integer
      • labour boolean

        Labour cost (ROT/RUT).

    • payments array<InvoicePayment>
      9 fields · each item
      • id integer
      • invoice_id string (uuid)
      • paid_on string (date)
      • amount_ore integer
      • currency string
      • account integer nullable

        Bank account the money came in on.

      • voucher_id string (uuid)
      • created_at string (date-time)
      • updated_at string (date-time)
    • created_at string (date-time)
    • updated_at string (date-time)

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Idempotent-Replayed

400 Bad Request – Bad request: missing or invalid Idempotency-Key, or a body that is not a JSON object.

All error codes · application/problem+json

  • idempotency_key_requiredNo Idempotency-Key on a POST

    Skicka en unik Idempotency-Key (till exempel ett UUID) med varje POST, så att ett nytt försök aldrig bokför två gånger.

  • idempotency_key_invalidIdempotency-Key too long or not visible ASCII

    Idempotency-Key ska vara 1–255 synliga ASCII-tecken.

  • invalid_jsonMalformed JSON

    Kroppen är inte giltig JSON (ett objekt).

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

401 Unauthorized – Missing, invalid, expired or revoked token or API key. Also returned when the person behind the credential has left the company (an OAuth grant is then revoked for good).

All error codes · application/problem+json

  • unauthenticatedNo valid credential

    Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, WWW-Authenticate

403 Forbidden – The credential may not do this: a scope is missing, the granting person no longer has the permission, the address is not allowed, the company is archived (read-only) or no longer allows the app.

All error codes · application/problem+json

  • insufficient_scopeScope missing or permission lost

    Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.

  • forbiddenThe action refuses (for example changing a posted voucher)

    Behörighet saknas för det här.

  • ip_not_allowedOutside the IP allowlist

    Företaget tillåter inte anrop från den här adressen.

  • company_archivedWrite to an archived company

    Företaget är arkiverat och kan bara läsas.

  • app_not_allowedThe company no longer allows the app

    Företaget tillåter inte längre den här appen.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

404 Not Found – Not found. Also the answer for another company's ids (existence is never revealed) and for every call while NONOX Connect is turned off for the company.

All error codes · application/problem+json

  • not_foundUnknown id, other company's id, or module off

    Det du söker finns inte.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

409 Conflict – A request with the same Idempotency-Key is still running.

All error codes · application/problem+json

  • idempotency_in_progressSame key, first request not finished

    En begäran med samma Idempotency-Key pågår. Vänta och försök igen.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Retry-After

415 Unsupported Media Type – The body is not application/json (or multipart/form-data where a file is accepted).

All error codes · application/problem+json

  • unsupported_media_typeWrong Content-Type

    Skicka JSON (application/json).

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

422 Unprocessable Content – Validation failed, or the Idempotency-Key was already used for a different request.

All error codes · application/problem+json

  • validation_failedField errors

    Uppgifterna kunde inte godtas. Se errors.

  • idempotency_key_reusedSame key, different body

    Idempotency-Key har redan använts för en annan begäran. Använd en ny nyckel för en ny begäran.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

429 Too Many Requests – Rate limit exceeded (per credential, per company or per address). Wait Retry-After seconds.

All error codes · application/problem+json

  • rate_limitedOver the limit

    För många anrop. Försök igen om 23 sekunder.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Retry-After

Code samples

curl
curl -X POST "https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/issue" \
  -H "Authorization: Bearer $NONOX_TOKEN" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: $(uuidgen)"
PHP (Laravel)
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;

$response = Http::withToken(config('services.nonox.token'))
    ->acceptJson()
    ->withHeaders(['Idempotency-Key' => (string) Str::uuid()])
    ->post('https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/issue');

$response->throw();

$data = $response->json('data');
PHP (Guzzle)
$client = new \GuzzleHttp\Client(['timeout' => 30]);

$response = $client->request('POST', 'https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/issue', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('NONOX_TOKEN'),
        'Accept' => 'application/json',
        'Idempotency-Key' => bin2hex(random_bytes(16)),
    ],
]);

$data = json_decode((string) $response->getBody(), true, flags: JSON_THROW_ON_ERROR)['data'];
JavaScript
const response = await fetch('https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/issue', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.NONOX_TOKEN}`,
    Accept: 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
});

if (!response.ok) {
  const problem = await response.json();
  throw new Error(`${problem.code}: ${problem.detail}`);
}

const { data } = await response.json();
Python
import os
import uuid
import requests

response = requests.post(
    "https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/issue",
    headers={
        "Authorization": f"Bearer {os.environ['NONOX_TOKEN']}",
        "Accept": "application/json",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    timeout=30,
)
response.raise_for_status()

data = response.json()["data"]

Responses · 200

application/json
{
  "data": {
    "id": "5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54",
    "number": 1042,
    "kind": "INVOICE",
    "status": "PAID",
    "credits_invoice_id": null,
    "customer_id": 18,
    "customer": {
      "number": 1004,
      "name": "Kund Exempel AB",
      "org_number": "559900-4560",
      "vat_number": "SE559900456001",
      "email": "faktura@kund.example.se",
      "address": {
        "line1": "Kundvägen 5",
        "line2": null,
        "postal_code": "222 33",
        "city": "Exempelby",
        "country": "SE"
      }
    },
    "invoice_date": "2026-03-02",
    "due_date": "2026-04-01",
    "delivery_date": null,
    "your_reference": "Anna Exempel",
    "our_reference": null,
    "notes": null,
    "reverse_charge": false,
    "foreign_sale": null,
    "tax_reduction": null,
    "tax_reduction_ore": 0,
    "property_designation": null,
    "currency": "SEK",
    "net_ore": 190000,
    "vat_ore": 47500,
    "rounding_ore": 0,
    "total_ore": 237500,
    "paid_ore": 237500,
    "remaining_ore": 0,
    "ocr": "104257",
    "voucher_id": "1d2e3f4a-5b6c-4d7e-8f9a-0b1c2d3e4f5a",
    "issued_at": "2026-03-02T10:45:12+01:00",
    "sent_at": "2026-03-02T10:45:12+01:00",
    "sent_to": "faktura@kund.example.se",
    "rows": [
      {
        "article": "TIM",
        "description": "Konsulttimme",
        "quantity": "2",
        "unit": "h",
        "unit_price_ore": 95000,
        "discount_bp": 0,
        "vat_rate": 2500,
        "account": 3001,
        "net_ore": 190000,
        "labour": false
      }
    ],
    "payments": [
      {
        "id": 88,
        "invoice_id": "5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54",
        "paid_on": "2026-03-28",
        "amount_ore": 237500,
        "currency": "SEK",
        "account": 1930,
        "voucher_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
        "created_at": "2026-03-28T09:12:00+01:00",
        "updated_at": "2026-03-28T09:12:00+01:00"
      }
    ],
    "created_at": "2026-03-02T10:45:12+01:00",
    "updated_at": "2026-03-28T09:12:00+01:00"
  }
}

Error

4003 examples
No Idempotency-Key on a POST
{
  "type": "urn:nonox:problem:idempotency_key_required",
  "title": "Bad Request",
  "status": 400,
  "code": "idempotency_key_required",
  "detail": "Skicka en unik Idempotency-Key (till exempel ett UUID) med varje POST, så att ett nytt försök aldrig bokför två gånger.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Idempotency-Key too long or not visible ASCII
{
  "type": "urn:nonox:problem:idempotency_key_invalid",
  "title": "Bad Request",
  "status": 400,
  "code": "idempotency_key_invalid",
  "detail": "Idempotency-Key ska vara 1–255 synliga ASCII-tecken.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Malformed JSON
{
  "type": "urn:nonox:problem:invalid_json",
  "title": "Bad Request",
  "status": 400,
  "code": "invalid_json",
  "detail": "Kroppen är inte giltig JSON (ett objekt).",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4011 example
No valid credential
{
  "type": "urn:nonox:problem:unauthenticated",
  "title": "Unauthorized",
  "status": 401,
  "code": "unauthenticated",
  "detail": "Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4035 examples
Scope missing or permission lost
{
  "type": "urn:nonox:problem:insufficient_scope",
  "title": "Forbidden",
  "status": 403,
  "code": "insufficient_scope",
  "detail": "Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17",
  "required_scopes": [
    "vouchers:post"
  ]
}
The action refuses (for example changing a posted voucher)
{
  "type": "urn:nonox:problem:forbidden",
  "title": "Forbidden",
  "status": 403,
  "code": "forbidden",
  "detail": "Behörighet saknas för det här.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Outside the IP allowlist
{
  "type": "urn:nonox:problem:ip_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "ip_not_allowed",
  "detail": "Företaget tillåter inte anrop från den här adressen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Write to an archived company
{
  "type": "urn:nonox:problem:company_archived",
  "title": "Forbidden",
  "status": 403,
  "code": "company_archived",
  "detail": "Företaget är arkiverat och kan bara läsas.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
The company no longer allows the app
{
  "type": "urn:nonox:problem:app_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "app_not_allowed",
  "detail": "Företaget tillåter inte längre den här appen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4041 example
Unknown id, other company's id, or module off
{
  "type": "urn:nonox:problem:not_found",
  "title": "Not Found",
  "status": 404,
  "code": "not_found",
  "detail": "Det du söker finns inte.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4091 example
Same key, first request not finished
{
  "type": "urn:nonox:problem:idempotency_in_progress",
  "title": "Conflict",
  "status": 409,
  "code": "idempotency_in_progress",
  "detail": "En begäran med samma Idempotency-Key pågår. Vänta och försök igen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4151 example
Wrong Content-Type
{
  "type": "urn:nonox:problem:unsupported_media_type",
  "title": "Unsupported Media Type",
  "status": 415,
  "code": "unsupported_media_type",
  "detail": "Skicka JSON (application/json).",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4222 examples
Field errors
{
  "type": "urn:nonox:problem:validation_failed",
  "title": "Unprocessable Content",
  "status": 422,
  "code": "validation_failed",
  "detail": "Uppgifterna kunde inte godtas. Se errors.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17",
  "errors": {
    "rows": [
      "Verifikationen balanserar inte: debet och kredit skiljer sig åt."
    ],
    "voucher_date": [
      "Det finns inget räkenskapsår som omfattar 2031-01-01."
    ]
  }
}
Same key, different body
{
  "type": "urn:nonox:problem:idempotency_key_reused",
  "title": "Unprocessable Content",
  "status": 422,
  "code": "idempotency_key_reused",
  "detail": "Idempotency-Key har redan använts för en annan begäran. Använd en ny nyckel för en ny begäran.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4291 example
Over the limit
{
  "type": "urn:nonox:problem:rate_limited",
  "title": "Too Many Requests",
  "status": 429,
  "code": "rate_limited",
  "detail": "För många anrop. Försök igen om 23 sekunder.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}

E-mail an issued invoice

POST /invoices/{invoice}/send sendInvoice

E-mails the issued invoice as a PDF to `email` or to the customer's address, and fires invoice.sent. A test company never e-mails anything. Same Action as the app (SendInvoice).

Scope

invoices:send

Parameters

  • invoice string (uuid) path required

    Invoice id (UUID, not the invoice number).

    Example: 5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54

  • Idempotency-Key string header required

    Required on every POST. A unique value per intended operation (a UUID v4 is ideal), 1–255 visible ASCII characters. Kept 24 hours per credential: the same key with the same request returns the stored response (Idempotent-Replayed: true); with a different request 422 idempotency_key_reused; while the first is still running 409. Server errors (5xx) are not stored, so retry with the same key.

    at least 1 characters · at most 255 characters · Example: 3f6c1b7e-2d4a-4e8b-9c0d-5a1b2c3d4e5f

Request body

application/jsonSendInvoiceInput

  • email string (email) nullable

    Default: the customer's e-mail on the invoice.

Responses

200 OK – The invoice, with sent_at and sent_to.

application/jsonobject

  • data Invoice required
    34 fields
    • id string (uuid)
    • number integer nullable

      Gapless invoice number, null while a draft.

    • kind string

      Values: INVOICE, CREDIT

    • status string

      Open enum.

      Values: DRAFT, ISSUED, PAID, CREDITED

    • credits_invoice_id string (uuid) nullable
    • customer_id integer
    • customer object

      The customer as on the invoice (frozen when issued). Never a personal number.

      6 fields
      • number integer nullable
      • name string nullable
      • org_number string nullable
      • vat_number string nullable
      • email string nullable
      • address object
        5 fields
        • line1 string nullable
        • line2 string nullable
        • postal_code string nullable
        • city string nullable
        • country string nullable
    • invoice_date string (date)
    • due_date string (date)
    • delivery_date string (date) nullable
    • your_reference string nullable
    • our_reference string nullable
    • notes string nullable
    • reverse_charge boolean
    • foreign_sale string nullable
    • tax_reduction string nullable

      ROT or RUT.

    • tax_reduction_ore integer
    • property_designation string nullable
    • currency string
    • net_ore integer
    • vat_ore integer
    • rounding_ore integer

      Öresavrundning to whole kronor.

    • total_ore integer
    • paid_ore integer
    • remaining_ore integer
    • ocr string nullable
    • voucher_id string (uuid) nullable
    • issued_at string (date-time) nullable
    • sent_at string (date-time) nullable
    • sent_to string nullable
    • rows array<InvoiceRow>
      10 fields · each item
      • article string nullable
      • description string
      • quantity string

        Decimal string, up to three decimals; negative on credit invoices.

      • unit string
      • unit_price_ore integer
      • discount_bp integer

        Discount in basis points (1000 is 10 %).

      • vat_rate integer
      • account integer nullable
      • net_ore integer
      • labour boolean

        Labour cost (ROT/RUT).

    • payments array<InvoicePayment>
      9 fields · each item
      • id integer
      • invoice_id string (uuid)
      • paid_on string (date)
      • amount_ore integer
      • currency string
      • account integer nullable

        Bank account the money came in on.

      • voucher_id string (uuid)
      • created_at string (date-time)
      • updated_at string (date-time)
    • created_at string (date-time)
    • updated_at string (date-time)

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Idempotent-Replayed

400 Bad Request – Bad request: missing or invalid Idempotency-Key, or a body that is not a JSON object.

All error codes · application/problem+json

  • idempotency_key_requiredNo Idempotency-Key on a POST

    Skicka en unik Idempotency-Key (till exempel ett UUID) med varje POST, så att ett nytt försök aldrig bokför två gånger.

  • idempotency_key_invalidIdempotency-Key too long or not visible ASCII

    Idempotency-Key ska vara 1–255 synliga ASCII-tecken.

  • invalid_jsonMalformed JSON

    Kroppen är inte giltig JSON (ett objekt).

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

401 Unauthorized – Missing, invalid, expired or revoked token or API key. Also returned when the person behind the credential has left the company (an OAuth grant is then revoked for good).

All error codes · application/problem+json

  • unauthenticatedNo valid credential

    Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, WWW-Authenticate

403 Forbidden – The credential may not do this: a scope is missing, the granting person no longer has the permission, the address is not allowed, the company is archived (read-only) or no longer allows the app.

All error codes · application/problem+json

  • insufficient_scopeScope missing or permission lost

    Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.

  • forbiddenThe action refuses (for example changing a posted voucher)

    Behörighet saknas för det här.

  • ip_not_allowedOutside the IP allowlist

    Företaget tillåter inte anrop från den här adressen.

  • company_archivedWrite to an archived company

    Företaget är arkiverat och kan bara läsas.

  • app_not_allowedThe company no longer allows the app

    Företaget tillåter inte längre den här appen.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

404 Not Found – Not found. Also the answer for another company's ids (existence is never revealed) and for every call while NONOX Connect is turned off for the company.

All error codes · application/problem+json

  • not_foundUnknown id, other company's id, or module off

    Det du söker finns inte.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

409 Conflict – A request with the same Idempotency-Key is still running.

All error codes · application/problem+json

  • idempotency_in_progressSame key, first request not finished

    En begäran med samma Idempotency-Key pågår. Vänta och försök igen.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Retry-After

415 Unsupported Media Type – The body is not application/json (or multipart/form-data where a file is accepted).

All error codes · application/problem+json

  • unsupported_media_typeWrong Content-Type

    Skicka JSON (application/json).

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

422 Unprocessable Content – Validation failed, or the Idempotency-Key was already used for a different request.

All error codes · application/problem+json

  • validation_failedField errors

    Uppgifterna kunde inte godtas. Se errors.

  • idempotency_key_reusedSame key, different body

    Idempotency-Key har redan använts för en annan begäran. Använd en ny nyckel för en ny begäran.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

429 Too Many Requests – Rate limit exceeded (per credential, per company or per address). Wait Retry-After seconds.

All error codes · application/problem+json

  • rate_limitedOver the limit

    För många anrop. Försök igen om 23 sekunder.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Retry-After

Code samples

curl
curl -X POST "https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/send" \
  -H "Authorization: Bearer $NONOX_TOKEN" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "faktura@kund.example.se"
}'
PHP (Laravel)
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;

$response = Http::withToken(config('services.nonox.token'))
    ->acceptJson()
    ->withHeaders(['Idempotency-Key' => (string) Str::uuid()])
    ->post('https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/send', [
        'email' => 'faktura@kund.example.se',
    ]);

$response->throw();

$data = $response->json('data');
PHP (Guzzle)
$client = new \GuzzleHttp\Client(['timeout' => 30]);

$response = $client->request('POST', 'https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/send', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('NONOX_TOKEN'),
        'Accept' => 'application/json',
        'Idempotency-Key' => bin2hex(random_bytes(16)),
    ],
    'json' => [
        'email' => 'faktura@kund.example.se',
    ],
]);

$data = json_decode((string) $response->getBody(), true, flags: JSON_THROW_ON_ERROR)['data'];
JavaScript
const response = await fetch('https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/send', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.NONOX_TOKEN}`,
    Accept: 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "email": "faktura@kund.example.se"
  }),
});

if (!response.ok) {
  const problem = await response.json();
  throw new Error(`${problem.code}: ${problem.detail}`);
}

const { data } = await response.json();
Python
import os
import uuid
import requests

response = requests.post(
    "https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/send",
    headers={
        "Authorization": f"Bearer {os.environ['NONOX_TOKEN']}",
        "Accept": "application/json",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "email": "faktura@kund.example.se",
    },
    timeout=30,
)
response.raise_for_status()

data = response.json()["data"]

Responses · 200

application/json
{
  "data": {
    "id": "5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54",
    "number": 1042,
    "kind": "INVOICE",
    "status": "PAID",
    "credits_invoice_id": null,
    "customer_id": 18,
    "customer": {
      "number": 1004,
      "name": "Kund Exempel AB",
      "org_number": "559900-4560",
      "vat_number": "SE559900456001",
      "email": "faktura@kund.example.se",
      "address": {
        "line1": "Kundvägen 5",
        "line2": null,
        "postal_code": "222 33",
        "city": "Exempelby",
        "country": "SE"
      }
    },
    "invoice_date": "2026-03-02",
    "due_date": "2026-04-01",
    "delivery_date": null,
    "your_reference": "Anna Exempel",
    "our_reference": null,
    "notes": null,
    "reverse_charge": false,
    "foreign_sale": null,
    "tax_reduction": null,
    "tax_reduction_ore": 0,
    "property_designation": null,
    "currency": "SEK",
    "net_ore": 190000,
    "vat_ore": 47500,
    "rounding_ore": 0,
    "total_ore": 237500,
    "paid_ore": 237500,
    "remaining_ore": 0,
    "ocr": "104257",
    "voucher_id": "1d2e3f4a-5b6c-4d7e-8f9a-0b1c2d3e4f5a",
    "issued_at": "2026-03-02T10:45:12+01:00",
    "sent_at": "2026-03-02T10:45:12+01:00",
    "sent_to": "faktura@kund.example.se",
    "rows": [
      {
        "article": "TIM",
        "description": "Konsulttimme",
        "quantity": "2",
        "unit": "h",
        "unit_price_ore": 95000,
        "discount_bp": 0,
        "vat_rate": 2500,
        "account": 3001,
        "net_ore": 190000,
        "labour": false
      }
    ],
    "payments": [
      {
        "id": 88,
        "invoice_id": "5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54",
        "paid_on": "2026-03-28",
        "amount_ore": 237500,
        "currency": "SEK",
        "account": 1930,
        "voucher_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
        "created_at": "2026-03-28T09:12:00+01:00",
        "updated_at": "2026-03-28T09:12:00+01:00"
      }
    ],
    "created_at": "2026-03-02T10:45:12+01:00",
    "updated_at": "2026-03-28T09:12:00+01:00"
  }
}

Error

4003 examples
No Idempotency-Key on a POST
{
  "type": "urn:nonox:problem:idempotency_key_required",
  "title": "Bad Request",
  "status": 400,
  "code": "idempotency_key_required",
  "detail": "Skicka en unik Idempotency-Key (till exempel ett UUID) med varje POST, så att ett nytt försök aldrig bokför två gånger.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Idempotency-Key too long or not visible ASCII
{
  "type": "urn:nonox:problem:idempotency_key_invalid",
  "title": "Bad Request",
  "status": 400,
  "code": "idempotency_key_invalid",
  "detail": "Idempotency-Key ska vara 1–255 synliga ASCII-tecken.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Malformed JSON
{
  "type": "urn:nonox:problem:invalid_json",
  "title": "Bad Request",
  "status": 400,
  "code": "invalid_json",
  "detail": "Kroppen är inte giltig JSON (ett objekt).",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4011 example
No valid credential
{
  "type": "urn:nonox:problem:unauthenticated",
  "title": "Unauthorized",
  "status": 401,
  "code": "unauthenticated",
  "detail": "Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4035 examples
Scope missing or permission lost
{
  "type": "urn:nonox:problem:insufficient_scope",
  "title": "Forbidden",
  "status": 403,
  "code": "insufficient_scope",
  "detail": "Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17",
  "required_scopes": [
    "vouchers:post"
  ]
}
The action refuses (for example changing a posted voucher)
{
  "type": "urn:nonox:problem:forbidden",
  "title": "Forbidden",
  "status": 403,
  "code": "forbidden",
  "detail": "Behörighet saknas för det här.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Outside the IP allowlist
{
  "type": "urn:nonox:problem:ip_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "ip_not_allowed",
  "detail": "Företaget tillåter inte anrop från den här adressen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Write to an archived company
{
  "type": "urn:nonox:problem:company_archived",
  "title": "Forbidden",
  "status": 403,
  "code": "company_archived",
  "detail": "Företaget är arkiverat och kan bara läsas.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
The company no longer allows the app
{
  "type": "urn:nonox:problem:app_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "app_not_allowed",
  "detail": "Företaget tillåter inte längre den här appen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4041 example
Unknown id, other company's id, or module off
{
  "type": "urn:nonox:problem:not_found",
  "title": "Not Found",
  "status": 404,
  "code": "not_found",
  "detail": "Det du söker finns inte.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4091 example
Same key, first request not finished
{
  "type": "urn:nonox:problem:idempotency_in_progress",
  "title": "Conflict",
  "status": 409,
  "code": "idempotency_in_progress",
  "detail": "En begäran med samma Idempotency-Key pågår. Vänta och försök igen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4151 example
Wrong Content-Type
{
  "type": "urn:nonox:problem:unsupported_media_type",
  "title": "Unsupported Media Type",
  "status": 415,
  "code": "unsupported_media_type",
  "detail": "Skicka JSON (application/json).",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4222 examples
Field errors
{
  "type": "urn:nonox:problem:validation_failed",
  "title": "Unprocessable Content",
  "status": 422,
  "code": "validation_failed",
  "detail": "Uppgifterna kunde inte godtas. Se errors.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17",
  "errors": {
    "rows": [
      "Verifikationen balanserar inte: debet och kredit skiljer sig åt."
    ],
    "voucher_date": [
      "Det finns inget räkenskapsår som omfattar 2031-01-01."
    ]
  }
}
Same key, different body
{
  "type": "urn:nonox:problem:idempotency_key_reused",
  "title": "Unprocessable Content",
  "status": 422,
  "code": "idempotency_key_reused",
  "detail": "Idempotency-Key har redan använts för en annan begäran. Använd en ny nyckel för en ny begäran.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4291 example
Over the limit
{
  "type": "urn:nonox:problem:rate_limited",
  "title": "Too Many Requests",
  "status": 429,
  "code": "rate_limited",
  "detail": "För många anrop. Försök igen om 23 sekunder.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}

Start a credit invoice

POST /invoices/{invoice}/credit creditInvoice

Creates a draft credit invoice for the whole of an unpaid invoice, with the same rows and negative quantities. It takes effect when issued with /issue, which closes both. Same Action as the app (CreditInvoice).

Scope

invoices:credit

Parameters

  • invoice string (uuid) path required

    Invoice id (UUID, not the invoice number).

    Example: 5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54

  • Idempotency-Key string header required

    Required on every POST. A unique value per intended operation (a UUID v4 is ideal), 1–255 visible ASCII characters. Kept 24 hours per credential: the same key with the same request returns the stored response (Idempotent-Replayed: true); with a different request 422 idempotency_key_reused; while the first is still running 409. Server errors (5xx) are not stored, so retry with the same key.

    at least 1 characters · at most 255 characters · Example: 3f6c1b7e-2d4a-4e8b-9c0d-5a1b2c3d4e5f

Responses

201 Created – The credit invoice draft.

application/jsonobject

  • data Invoice required
    34 fields
    • id string (uuid)
    • number integer nullable

      Gapless invoice number, null while a draft.

    • kind string

      Values: INVOICE, CREDIT

    • status string

      Open enum.

      Values: DRAFT, ISSUED, PAID, CREDITED

    • credits_invoice_id string (uuid) nullable
    • customer_id integer
    • customer object

      The customer as on the invoice (frozen when issued). Never a personal number.

      6 fields
      • number integer nullable
      • name string nullable
      • org_number string nullable
      • vat_number string nullable
      • email string nullable
      • address object
        5 fields
        • line1 string nullable
        • line2 string nullable
        • postal_code string nullable
        • city string nullable
        • country string nullable
    • invoice_date string (date)
    • due_date string (date)
    • delivery_date string (date) nullable
    • your_reference string nullable
    • our_reference string nullable
    • notes string nullable
    • reverse_charge boolean
    • foreign_sale string nullable
    • tax_reduction string nullable

      ROT or RUT.

    • tax_reduction_ore integer
    • property_designation string nullable
    • currency string
    • net_ore integer
    • vat_ore integer
    • rounding_ore integer

      Öresavrundning to whole kronor.

    • total_ore integer
    • paid_ore integer
    • remaining_ore integer
    • ocr string nullable
    • voucher_id string (uuid) nullable
    • issued_at string (date-time) nullable
    • sent_at string (date-time) nullable
    • sent_to string nullable
    • rows array<InvoiceRow>
      10 fields · each item
      • article string nullable
      • description string
      • quantity string

        Decimal string, up to three decimals; negative on credit invoices.

      • unit string
      • unit_price_ore integer
      • discount_bp integer

        Discount in basis points (1000 is 10 %).

      • vat_rate integer
      • account integer nullable
      • net_ore integer
      • labour boolean

        Labour cost (ROT/RUT).

    • payments array<InvoicePayment>
      9 fields · each item
      • id integer
      • invoice_id string (uuid)
      • paid_on string (date)
      • amount_ore integer
      • currency string
      • account integer nullable

        Bank account the money came in on.

      • voucher_id string (uuid)
      • created_at string (date-time)
      • updated_at string (date-time)
    • created_at string (date-time)
    • updated_at string (date-time)

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Location, Idempotent-Replayed

400 Bad Request – Bad request: missing or invalid Idempotency-Key, or a body that is not a JSON object.

All error codes · application/problem+json

  • idempotency_key_requiredNo Idempotency-Key on a POST

    Skicka en unik Idempotency-Key (till exempel ett UUID) med varje POST, så att ett nytt försök aldrig bokför två gånger.

  • idempotency_key_invalidIdempotency-Key too long or not visible ASCII

    Idempotency-Key ska vara 1–255 synliga ASCII-tecken.

  • invalid_jsonMalformed JSON

    Kroppen är inte giltig JSON (ett objekt).

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

401 Unauthorized – Missing, invalid, expired or revoked token or API key. Also returned when the person behind the credential has left the company (an OAuth grant is then revoked for good).

All error codes · application/problem+json

  • unauthenticatedNo valid credential

    Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, WWW-Authenticate

403 Forbidden – The credential may not do this: a scope is missing, the granting person no longer has the permission, the address is not allowed, the company is archived (read-only) or no longer allows the app.

All error codes · application/problem+json

  • insufficient_scopeScope missing or permission lost

    Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.

  • forbiddenThe action refuses (for example changing a posted voucher)

    Behörighet saknas för det här.

  • ip_not_allowedOutside the IP allowlist

    Företaget tillåter inte anrop från den här adressen.

  • company_archivedWrite to an archived company

    Företaget är arkiverat och kan bara läsas.

  • app_not_allowedThe company no longer allows the app

    Företaget tillåter inte längre den här appen.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

404 Not Found – Not found. Also the answer for another company's ids (existence is never revealed) and for every call while NONOX Connect is turned off for the company.

All error codes · application/problem+json

  • not_foundUnknown id, other company's id, or module off

    Det du söker finns inte.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

409 Conflict – A request with the same Idempotency-Key is still running.

All error codes · application/problem+json

  • idempotency_in_progressSame key, first request not finished

    En begäran med samma Idempotency-Key pågår. Vänta och försök igen.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Retry-After

415 Unsupported Media Type – The body is not application/json (or multipart/form-data where a file is accepted).

All error codes · application/problem+json

  • unsupported_media_typeWrong Content-Type

    Skicka JSON (application/json).

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

422 Unprocessable Content – Validation failed, or the Idempotency-Key was already used for a different request.

All error codes · application/problem+json

  • validation_failedField errors

    Uppgifterna kunde inte godtas. Se errors.

  • idempotency_key_reusedSame key, different body

    Idempotency-Key har redan använts för en annan begäran. Använd en ny nyckel för en ny begäran.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

429 Too Many Requests – Rate limit exceeded (per credential, per company or per address). Wait Retry-After seconds.

All error codes · application/problem+json

  • rate_limitedOver the limit

    För många anrop. Försök igen om 23 sekunder.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Retry-After

Code samples

curl
curl -X POST "https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/credit" \
  -H "Authorization: Bearer $NONOX_TOKEN" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: $(uuidgen)"
PHP (Laravel)
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;

$response = Http::withToken(config('services.nonox.token'))
    ->acceptJson()
    ->withHeaders(['Idempotency-Key' => (string) Str::uuid()])
    ->post('https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/credit');

$response->throw();

$data = $response->json('data');
PHP (Guzzle)
$client = new \GuzzleHttp\Client(['timeout' => 30]);

$response = $client->request('POST', 'https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/credit', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('NONOX_TOKEN'),
        'Accept' => 'application/json',
        'Idempotency-Key' => bin2hex(random_bytes(16)),
    ],
]);

$data = json_decode((string) $response->getBody(), true, flags: JSON_THROW_ON_ERROR)['data'];
JavaScript
const response = await fetch('https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/credit', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.NONOX_TOKEN}`,
    Accept: 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
});

if (!response.ok) {
  const problem = await response.json();
  throw new Error(`${problem.code}: ${problem.detail}`);
}

const { data } = await response.json();
Python
import os
import uuid
import requests

response = requests.post(
    "https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/credit",
    headers={
        "Authorization": f"Bearer {os.environ['NONOX_TOKEN']}",
        "Accept": "application/json",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    timeout=30,
)
response.raise_for_status()

data = response.json()["data"]

Responses · 201

application/json
{
  "data": {
    "id": "5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54",
    "number": 1042,
    "kind": "INVOICE",
    "status": "PAID",
    "credits_invoice_id": null,
    "customer_id": 18,
    "customer": {
      "number": 1004,
      "name": "Kund Exempel AB",
      "org_number": "559900-4560",
      "vat_number": "SE559900456001",
      "email": "faktura@kund.example.se",
      "address": {
        "line1": "Kundvägen 5",
        "line2": null,
        "postal_code": "222 33",
        "city": "Exempelby",
        "country": "SE"
      }
    },
    "invoice_date": "2026-03-02",
    "due_date": "2026-04-01",
    "delivery_date": null,
    "your_reference": "Anna Exempel",
    "our_reference": null,
    "notes": null,
    "reverse_charge": false,
    "foreign_sale": null,
    "tax_reduction": null,
    "tax_reduction_ore": 0,
    "property_designation": null,
    "currency": "SEK",
    "net_ore": 190000,
    "vat_ore": 47500,
    "rounding_ore": 0,
    "total_ore": 237500,
    "paid_ore": 237500,
    "remaining_ore": 0,
    "ocr": "104257",
    "voucher_id": "1d2e3f4a-5b6c-4d7e-8f9a-0b1c2d3e4f5a",
    "issued_at": "2026-03-02T10:45:12+01:00",
    "sent_at": "2026-03-02T10:45:12+01:00",
    "sent_to": "faktura@kund.example.se",
    "rows": [
      {
        "article": "TIM",
        "description": "Konsulttimme",
        "quantity": "2",
        "unit": "h",
        "unit_price_ore": 95000,
        "discount_bp": 0,
        "vat_rate": 2500,
        "account": 3001,
        "net_ore": 190000,
        "labour": false
      }
    ],
    "payments": [
      {
        "id": 88,
        "invoice_id": "5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54",
        "paid_on": "2026-03-28",
        "amount_ore": 237500,
        "currency": "SEK",
        "account": 1930,
        "voucher_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
        "created_at": "2026-03-28T09:12:00+01:00",
        "updated_at": "2026-03-28T09:12:00+01:00"
      }
    ],
    "created_at": "2026-03-02T10:45:12+01:00",
    "updated_at": "2026-03-28T09:12:00+01:00"
  }
}

Error

4003 examples
No Idempotency-Key on a POST
{
  "type": "urn:nonox:problem:idempotency_key_required",
  "title": "Bad Request",
  "status": 400,
  "code": "idempotency_key_required",
  "detail": "Skicka en unik Idempotency-Key (till exempel ett UUID) med varje POST, så att ett nytt försök aldrig bokför två gånger.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Idempotency-Key too long or not visible ASCII
{
  "type": "urn:nonox:problem:idempotency_key_invalid",
  "title": "Bad Request",
  "status": 400,
  "code": "idempotency_key_invalid",
  "detail": "Idempotency-Key ska vara 1–255 synliga ASCII-tecken.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Malformed JSON
{
  "type": "urn:nonox:problem:invalid_json",
  "title": "Bad Request",
  "status": 400,
  "code": "invalid_json",
  "detail": "Kroppen är inte giltig JSON (ett objekt).",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4011 example
No valid credential
{
  "type": "urn:nonox:problem:unauthenticated",
  "title": "Unauthorized",
  "status": 401,
  "code": "unauthenticated",
  "detail": "Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4035 examples
Scope missing or permission lost
{
  "type": "urn:nonox:problem:insufficient_scope",
  "title": "Forbidden",
  "status": 403,
  "code": "insufficient_scope",
  "detail": "Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17",
  "required_scopes": [
    "vouchers:post"
  ]
}
The action refuses (for example changing a posted voucher)
{
  "type": "urn:nonox:problem:forbidden",
  "title": "Forbidden",
  "status": 403,
  "code": "forbidden",
  "detail": "Behörighet saknas för det här.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Outside the IP allowlist
{
  "type": "urn:nonox:problem:ip_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "ip_not_allowed",
  "detail": "Företaget tillåter inte anrop från den här adressen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Write to an archived company
{
  "type": "urn:nonox:problem:company_archived",
  "title": "Forbidden",
  "status": 403,
  "code": "company_archived",
  "detail": "Företaget är arkiverat och kan bara läsas.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
The company no longer allows the app
{
  "type": "urn:nonox:problem:app_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "app_not_allowed",
  "detail": "Företaget tillåter inte längre den här appen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4041 example
Unknown id, other company's id, or module off
{
  "type": "urn:nonox:problem:not_found",
  "title": "Not Found",
  "status": 404,
  "code": "not_found",
  "detail": "Det du söker finns inte.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4091 example
Same key, first request not finished
{
  "type": "urn:nonox:problem:idempotency_in_progress",
  "title": "Conflict",
  "status": 409,
  "code": "idempotency_in_progress",
  "detail": "En begäran med samma Idempotency-Key pågår. Vänta och försök igen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4151 example
Wrong Content-Type
{
  "type": "urn:nonox:problem:unsupported_media_type",
  "title": "Unsupported Media Type",
  "status": 415,
  "code": "unsupported_media_type",
  "detail": "Skicka JSON (application/json).",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4222 examples
Field errors
{
  "type": "urn:nonox:problem:validation_failed",
  "title": "Unprocessable Content",
  "status": 422,
  "code": "validation_failed",
  "detail": "Uppgifterna kunde inte godtas. Se errors.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17",
  "errors": {
    "rows": [
      "Verifikationen balanserar inte: debet och kredit skiljer sig åt."
    ],
    "voucher_date": [
      "Det finns inget räkenskapsår som omfattar 2031-01-01."
    ]
  }
}
Same key, different body
{
  "type": "urn:nonox:problem:idempotency_key_reused",
  "title": "Unprocessable Content",
  "status": 422,
  "code": "idempotency_key_reused",
  "detail": "Idempotency-Key har redan använts för en annan begäran. Använd en ny nyckel för en ny begäran.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4291 example
Over the limit
{
  "type": "urn:nonox:problem:rate_limited",
  "title": "Too Many Requests",
  "status": 429,
  "code": "rate_limited",
  "detail": "För många anrop. Försök igen om 23 sekunder.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}

Register a payment

POST /invoices/{invoice}/payments registerInvoicePayment

Registers money received, booked in series C; the invoice is PAID when nothing remains (and invoice.paid is sent). More than what remains answers 422. Books a voucher as the person behind the credential, so the credential also needs vouchers:create and vouchers:post. Same Action as the app (RegisterPayment).

Scope

payments:create + vouchers:create + vouchers:post

Parameters

  • invoice string (uuid) path required

    Invoice id (UUID, not the invoice number).

    Example: 5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54

  • Idempotency-Key string header required

    Required on every POST. A unique value per intended operation (a UUID v4 is ideal), 1–255 visible ASCII characters. Kept 24 hours per credential: the same key with the same request returns the stored response (Idempotent-Replayed: true); with a different request 422 idempotency_key_reused; while the first is still running 409. Server errors (5xx) are not stored, so retry with the same key.

    at least 1 characters · at most 255 characters · Example: 3f6c1b7e-2d4a-4e8b-9c0d-5a1b2c3d4e5f

Request body

application/jsonPaymentInput required

  • paid_on string (date) required
  • amount_ore integer required

    minimum 1

  • account integer nullable

    Bank account; default 1930.

    minimum 1900 · maximum 1999

Responses

201 Created – The payment.

application/jsonobject

  • data InvoicePayment required
    9 fields
    • id integer
    • invoice_id string (uuid)
    • paid_on string (date)
    • amount_ore integer
    • currency string
    • account integer nullable

      Bank account the money came in on.

    • voucher_id string (uuid)
    • created_at string (date-time)
    • updated_at string (date-time)

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Location, Idempotent-Replayed

400 Bad Request – Bad request: missing or invalid Idempotency-Key, or a body that is not a JSON object.

All error codes · application/problem+json

  • idempotency_key_requiredNo Idempotency-Key on a POST

    Skicka en unik Idempotency-Key (till exempel ett UUID) med varje POST, så att ett nytt försök aldrig bokför två gånger.

  • idempotency_key_invalidIdempotency-Key too long or not visible ASCII

    Idempotency-Key ska vara 1–255 synliga ASCII-tecken.

  • invalid_jsonMalformed JSON

    Kroppen är inte giltig JSON (ett objekt).

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

401 Unauthorized – Missing, invalid, expired or revoked token or API key. Also returned when the person behind the credential has left the company (an OAuth grant is then revoked for good).

All error codes · application/problem+json

  • unauthenticatedNo valid credential

    Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, WWW-Authenticate

403 Forbidden – The credential may not do this: a scope is missing, the granting person no longer has the permission, the address is not allowed, the company is archived (read-only) or no longer allows the app.

All error codes · application/problem+json

  • insufficient_scopeScope missing or permission lost

    Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.

  • forbiddenThe action refuses (for example changing a posted voucher)

    Behörighet saknas för det här.

  • ip_not_allowedOutside the IP allowlist

    Företaget tillåter inte anrop från den här adressen.

  • company_archivedWrite to an archived company

    Företaget är arkiverat och kan bara läsas.

  • app_not_allowedThe company no longer allows the app

    Företaget tillåter inte längre den här appen.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

404 Not Found – Not found. Also the answer for another company's ids (existence is never revealed) and for every call while NONOX Connect is turned off for the company.

All error codes · application/problem+json

  • not_foundUnknown id, other company's id, or module off

    Det du söker finns inte.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

409 Conflict – A request with the same Idempotency-Key is still running.

All error codes · application/problem+json

  • idempotency_in_progressSame key, first request not finished

    En begäran med samma Idempotency-Key pågår. Vänta och försök igen.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Retry-After

415 Unsupported Media Type – The body is not application/json (or multipart/form-data where a file is accepted).

All error codes · application/problem+json

  • unsupported_media_typeWrong Content-Type

    Skicka JSON (application/json).

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

422 Unprocessable Content – Validation failed, or the Idempotency-Key was already used for a different request.

All error codes · application/problem+json

  • validation_failedField errors

    Uppgifterna kunde inte godtas. Se errors.

  • idempotency_key_reusedSame key, different body

    Idempotency-Key har redan använts för en annan begäran. Använd en ny nyckel för en ny begäran.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

429 Too Many Requests – Rate limit exceeded (per credential, per company or per address). Wait Retry-After seconds.

All error codes · application/problem+json

  • rate_limitedOver the limit

    För många anrop. Försök igen om 23 sekunder.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Retry-After

Code samples

curl
curl -X POST "https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/payments" \
  -H "Authorization: Bearer $NONOX_TOKEN" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "paid_on": "2026-03-28",
  "amount_ore": 237500
}'
PHP (Laravel)
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;

$response = Http::withToken(config('services.nonox.token'))
    ->acceptJson()
    ->withHeaders(['Idempotency-Key' => (string) Str::uuid()])
    ->post('https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/payments', [
        'paid_on' => '2026-03-28',
        'amount_ore' => 237500,
    ]);

$response->throw();

$data = $response->json('data');
PHP (Guzzle)
$client = new \GuzzleHttp\Client(['timeout' => 30]);

$response = $client->request('POST', 'https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/payments', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('NONOX_TOKEN'),
        'Accept' => 'application/json',
        'Idempotency-Key' => bin2hex(random_bytes(16)),
    ],
    'json' => [
        'paid_on' => '2026-03-28',
        'amount_ore' => 237500,
    ],
]);

$data = json_decode((string) $response->getBody(), true, flags: JSON_THROW_ON_ERROR)['data'];
JavaScript
const response = await fetch('https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/payments', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.NONOX_TOKEN}`,
    Accept: 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "paid_on": "2026-03-28",
    "amount_ore": 237500
  }),
});

if (!response.ok) {
  const problem = await response.json();
  throw new Error(`${problem.code}: ${problem.detail}`);
}

const { data } = await response.json();
Python
import os
import uuid
import requests

response = requests.post(
    "https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/payments",
    headers={
        "Authorization": f"Bearer {os.environ['NONOX_TOKEN']}",
        "Accept": "application/json",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "paid_on": "2026-03-28",
        "amount_ore": 237500,
    },
    timeout=30,
)
response.raise_for_status()

data = response.json()["data"]

Responses · 201

application/json
{
  "data": {
    "id": 88,
    "invoice_id": "5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54",
    "paid_on": "2026-03-28",
    "amount_ore": 237500,
    "currency": "SEK",
    "account": 1930,
    "voucher_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
    "created_at": "2026-03-28T09:12:00+01:00",
    "updated_at": "2026-03-28T09:12:00+01:00"
  }
}

Error

4003 examples
No Idempotency-Key on a POST
{
  "type": "urn:nonox:problem:idempotency_key_required",
  "title": "Bad Request",
  "status": 400,
  "code": "idempotency_key_required",
  "detail": "Skicka en unik Idempotency-Key (till exempel ett UUID) med varje POST, så att ett nytt försök aldrig bokför två gånger.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Idempotency-Key too long or not visible ASCII
{
  "type": "urn:nonox:problem:idempotency_key_invalid",
  "title": "Bad Request",
  "status": 400,
  "code": "idempotency_key_invalid",
  "detail": "Idempotency-Key ska vara 1–255 synliga ASCII-tecken.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Malformed JSON
{
  "type": "urn:nonox:problem:invalid_json",
  "title": "Bad Request",
  "status": 400,
  "code": "invalid_json",
  "detail": "Kroppen är inte giltig JSON (ett objekt).",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4011 example
No valid credential
{
  "type": "urn:nonox:problem:unauthenticated",
  "title": "Unauthorized",
  "status": 401,
  "code": "unauthenticated",
  "detail": "Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4035 examples
Scope missing or permission lost
{
  "type": "urn:nonox:problem:insufficient_scope",
  "title": "Forbidden",
  "status": 403,
  "code": "insufficient_scope",
  "detail": "Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17",
  "required_scopes": [
    "vouchers:post"
  ]
}
The action refuses (for example changing a posted voucher)
{
  "type": "urn:nonox:problem:forbidden",
  "title": "Forbidden",
  "status": 403,
  "code": "forbidden",
  "detail": "Behörighet saknas för det här.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Outside the IP allowlist
{
  "type": "urn:nonox:problem:ip_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "ip_not_allowed",
  "detail": "Företaget tillåter inte anrop från den här adressen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Write to an archived company
{
  "type": "urn:nonox:problem:company_archived",
  "title": "Forbidden",
  "status": 403,
  "code": "company_archived",
  "detail": "Företaget är arkiverat och kan bara läsas.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
The company no longer allows the app
{
  "type": "urn:nonox:problem:app_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "app_not_allowed",
  "detail": "Företaget tillåter inte längre den här appen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4041 example
Unknown id, other company's id, or module off
{
  "type": "urn:nonox:problem:not_found",
  "title": "Not Found",
  "status": 404,
  "code": "not_found",
  "detail": "Det du söker finns inte.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4091 example
Same key, first request not finished
{
  "type": "urn:nonox:problem:idempotency_in_progress",
  "title": "Conflict",
  "status": 409,
  "code": "idempotency_in_progress",
  "detail": "En begäran med samma Idempotency-Key pågår. Vänta och försök igen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4151 example
Wrong Content-Type
{
  "type": "urn:nonox:problem:unsupported_media_type",
  "title": "Unsupported Media Type",
  "status": 415,
  "code": "unsupported_media_type",
  "detail": "Skicka JSON (application/json).",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4222 examples
Field errors
{
  "type": "urn:nonox:problem:validation_failed",
  "title": "Unprocessable Content",
  "status": 422,
  "code": "validation_failed",
  "detail": "Uppgifterna kunde inte godtas. Se errors.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17",
  "errors": {
    "rows": [
      "Verifikationen balanserar inte: debet och kredit skiljer sig åt."
    ],
    "voucher_date": [
      "Det finns inget räkenskapsår som omfattar 2031-01-01."
    ]
  }
}
Same key, different body
{
  "type": "urn:nonox:problem:idempotency_key_reused",
  "title": "Unprocessable Content",
  "status": 422,
  "code": "idempotency_key_reused",
  "detail": "Idempotency-Key har redan använts för en annan begäran. Använd en ny nyckel för en ny begäran.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4291 example
Over the limit
{
  "type": "urn:nonox:problem:rate_limited",
  "title": "Too Many Requests",
  "status": 429,
  "code": "rate_limited",
  "detail": "För många anrop. Försök igen om 23 sekunder.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}

Download the invoice as PDF

GET /invoices/{invoice}/pdf getInvoicePdf

The invoice in NONOX's own layout, as a PDF (a draft is marked as one). Counts toward the company's hourly PDF quota; above it 429.

Scope

invoices:view

Parameters

  • invoice string (uuid) path required

    Invoice id (UUID, not the invoice number).

    Example: 5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54

Responses

200 OK – The PDF.

application/pdfstring

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

401 Unauthorized – Missing, invalid, expired or revoked token or API key. Also returned when the person behind the credential has left the company (an OAuth grant is then revoked for good).

All error codes · application/problem+json

  • unauthenticatedNo valid credential

    Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, WWW-Authenticate

403 Forbidden – The credential may not do this: a scope is missing, the granting person no longer has the permission, the address is not allowed, the company is archived (read-only) or no longer allows the app.

All error codes · application/problem+json

  • insufficient_scopeScope missing or permission lost

    Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.

  • forbiddenThe action refuses (for example changing a posted voucher)

    Behörighet saknas för det här.

  • ip_not_allowedOutside the IP allowlist

    Företaget tillåter inte anrop från den här adressen.

  • company_archivedWrite to an archived company

    Företaget är arkiverat och kan bara läsas.

  • app_not_allowedThe company no longer allows the app

    Företaget tillåter inte längre den här appen.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

404 Not Found – Not found. Also the answer for another company's ids (existence is never revealed) and for every call while NONOX Connect is turned off for the company.

All error codes · application/problem+json

  • not_foundUnknown id, other company's id, or module off

    Det du söker finns inte.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

429 Too Many Requests – Rate limit exceeded (per credential, per company or per address). Wait Retry-After seconds.

All error codes · application/problem+json

  • rate_limitedOver the limit

    För många anrop. Försök igen om 23 sekunder.

Response headers: X-Request-Id, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Retry-After

Code samples

curl
curl "https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/pdf" \
  -H "Authorization: Bearer $NONOX_TOKEN" \
  -H "Accept: application/json" \
  -o kvitto.pdf
PHP (Laravel)
use Illuminate\Support\Facades\Http;

$response = Http::withToken(config('services.nonox.token'))
    ->acceptJson()
    ->get('https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/pdf');

$response->throw();

file_put_contents('kvitto.pdf', $response->body());
PHP (Guzzle)
$client = new \GuzzleHttp\Client(['timeout' => 30]);

$response = $client->request('GET', 'https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/pdf', [
    'headers' => [
        'Authorization' => 'Bearer '.getenv('NONOX_TOKEN'),
        'Accept' => 'application/json',
    ],
    'sink' => 'kvitto.pdf',
]);
JavaScript
const response = await fetch('https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/pdf', {
  headers: {
    Authorization: `Bearer ${process.env.NONOX_TOKEN}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const problem = await response.json();
  throw new Error(`${problem.code}: ${problem.detail}`);
}

const file = Buffer.from(await response.arrayBuffer());
Python
import os
import requests

response = requests.get(
    "https://nonox.app/api/v1/invoices/5c2e8a41-7b3d-4f19-a6c2-0e9d8b7a6f54/pdf",
    headers={
        "Authorization": f"Bearer {os.environ['NONOX_TOKEN']}",
        "Accept": "application/json",
    },
    timeout=30,
)
response.raise_for_status()

with open("kvitto.pdf", "wb") as file:
    file.write(response.content)

Error

4011 example
No valid credential
{
  "type": "urn:nonox:problem:unauthenticated",
  "title": "Unauthorized",
  "status": 401,
  "code": "unauthenticated",
  "detail": "Nyckeln eller token saknas, är ogiltig, har gått ut eller har återkallats.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4035 examples
Scope missing or permission lost
{
  "type": "urn:nonox:problem:insufficient_scope",
  "title": "Forbidden",
  "status": 403,
  "code": "insufficient_scope",
  "detail": "Nyckeln eller appen saknar behörigheten vouchers:post, eller så har personen som gav den inte längre den behörigheten i företaget.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17",
  "required_scopes": [
    "vouchers:post"
  ]
}
The action refuses (for example changing a posted voucher)
{
  "type": "urn:nonox:problem:forbidden",
  "title": "Forbidden",
  "status": 403,
  "code": "forbidden",
  "detail": "Behörighet saknas för det här.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Outside the IP allowlist
{
  "type": "urn:nonox:problem:ip_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "ip_not_allowed",
  "detail": "Företaget tillåter inte anrop från den här adressen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
Write to an archived company
{
  "type": "urn:nonox:problem:company_archived",
  "title": "Forbidden",
  "status": 403,
  "code": "company_archived",
  "detail": "Företaget är arkiverat och kan bara läsas.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
The company no longer allows the app
{
  "type": "urn:nonox:problem:app_not_allowed",
  "title": "Forbidden",
  "status": 403,
  "code": "app_not_allowed",
  "detail": "Företaget tillåter inte längre den här appen.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4041 example
Unknown id, other company's id, or module off
{
  "type": "urn:nonox:problem:not_found",
  "title": "Not Found",
  "status": 404,
  "code": "not_found",
  "detail": "Det du söker finns inte.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}
4291 example
Over the limit
{
  "type": "urn:nonox:problem:rate_limited",
  "title": "Too Many Requests",
  "status": 429,
  "code": "rate_limited",
  "detail": "För många anrop. Försök igen om 23 sekunder.",
  "instance": "urn:nonox:request:7f3c2a9e-4b1d-4c8e-9a51-2d6f0e8b3c17"
}