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:
- Create an account through the Emfakt dashboard.
- Log in with
POST /v1/loginto get a control-plane access token. - Create an organization with
POST /v1/control-plane/organizations. - 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.
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.
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" } }'{ "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" }}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.
curl "https://api-sandbox.emfakt.com/v1/invoices/inv_2kCYq4m4G7YbUjvH0kC1dg" \ -H "Authorization: Bearer <YOUR_API_KEY>"{ "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" }}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.
curl "https://api-sandbox.emfakt.com/v1/invoices/inv_2kCYq4m4G7YbUjvH0kC1dg/upo" \ -H "Authorization: Bearer <YOUR_API_KEY>" \ -H "Accept: application/xml"<?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:
- Authentication for control-plane JWT versus developer API-key auth.
- Idempotency before retrying invoice submissions.
- Sandbox and live mode before using
sk_live_.... - Invoices for endpoint details.