Quickstart

Follow this path to submit a sandbox invoice, read its state, and retrieve UPO XML when it becomes available. The setup steps stay brief so you can get to the first invoice quickly.

Setup summary

Before calling the developer invoice API, you need a test developer API key.

The setup flow is:

  1. Create an account through the Emfakt dashboard.
  2. Log in with POST /v1/login to get a control-plane access token.
  3. Create an organization with POST /v1/control-plane/organizations.
  4. Create a test API key with POST /v1/control-plane/api-keys.

Those setup calls use the control-plane API. The raw sk_test_... key is returned only once when it is created. Store it securely.

Setup calls use the control-plane API and a JWT access token. Invoice calls use the developer API key you create here.

POST/v1/invoices

Submit a sandbox invoice

Use the returned sk_test_... key as a bearer token. Idempotency-Key is required for invoice submission.

The optional Ksef-Sandbox-Scenario header applies only to test-mode invoice submissions. If omitted, the scenario defaults to accepted.

Submit sandbox invoice
curl -X POST "https://api-sandbox.emfakt.com/v1/invoices" \  -H "Authorization: Bearer <YOUR_API_KEY>" \  -H "Content-Type: application/json" \  -H "Idempotency-Key: inv-submit-sandbox-fv-0001" \  -H "Ksef-Sandbox-Scenario: accepted" \  -d '{    "external_id": "sandbox-fv-0001",    "invoice_xml": "<emfakt_sandbox_invoice><scenario>accepted</scenario><external_id>sandbox-fv-0001</external_id></emfakt_sandbox_invoice>",    "metadata": {      "order_id": "ord_123"    }  }'
201 response
{  "id": "inv_2kCYq4m4G7YbUjvH0kC1dg",  "object": "invoice",  "mode": "test",  "status": "processing",  "organization_id": "org_2kCYq4m4G7YbUjvH0kC1dg",  "external_id": "fv-2026-0001",  "created_at": "2026-05-31T10:15:30Z",  "updated_at": "2026-05-31T10:15:30Z",  "ksef_number": null,  "upo_available": false,  "retrying": false,  "next_retry_at": null,  "last_error": null,  "metadata": {    "order_id": "ord_123"  }}
GET/v1/invoices/{id}

Retrieve invoice state

Poll the invoice read endpoint to observe the stored product state. Do not submit the same invoice with a new idempotency key just to check status.

Retrieve invoice
curl "https://api-sandbox.emfakt.com/v1/invoices/inv_2kCYq4m4G7YbUjvH0kC1dg" \  -H "Authorization: Bearer <YOUR_API_KEY>"
Accepted sandbox invoice
{  "id": "inv_2kCYq4m4G7YbUjvH0kC1dg",  "object": "invoice",  "mode": "test",  "status": "accepted",  "organization_id": "org_2kCYq4m4G7YbUjvH0kC1dg",  "external_id": "fv-2026-0001",  "created_at": "2026-05-31T10:15:30Z",  "updated_at": "2026-05-31T10:18:30Z",  "ksef_number": "KSEF-TEST-8D7C6B5A4E3F2A1B0C9D",  "upo_available": true,  "retrying": false,  "next_retry_at": null,  "last_error": null,  "metadata": {    "order_id": "ord_123"  }}
GET/v1/invoices/{id}/upo

Retrieve UPO when available

Call the UPO endpoint only after the invoice shows upo_available: true.

The endpoint returns persisted XML only. It does not call KSeF live during the GET request.

Retrieve UPO XML
curl "https://api-sandbox.emfakt.com/v1/invoices/inv_2kCYq4m4G7YbUjvH0kC1dg/upo" \  -H "Authorization: Bearer <YOUR_API_KEY>" \  -H "Accept: application/xml"
200 sandbox XML response
<?xml version="1.0" encoding="UTF-8"?><emfakt_sandbox_upo>  <object>sandbox_upo</object>  <artifact_type>upo_xml</artifact_type>  <sandbox>true</sandbox>  <test_data>true</test_data>  <invoice_id>inv_2kCYq4m4G7YbUjvH0kC1dg</invoice_id>  <organization_id>org_2kCYq4m4G7YbUjvH0kC1dg</organization_id>  <ksef_number>KSEF-TEST-8D7C6B5A4E3F2A1B0C9D</ksef_number>  <accepted_at>2026-05-31T10:18:30Z</accepted_at>  <available_at>2026-05-31T10:18:30Z</available_at>  <notice>Product-owned simulated sandbox artifact for developer testing only. Not valid for tax or production use.</notice></emfakt_sandbox_upo>

Next steps

Read: