Quickstart: First Invoice in 5 Minutes¶
This walks through the full journey from registration to sending your first invoice. All examples use gRPC with JSON transcoding (REST).
Prerequisites¶
- An Invora account at dashboard.invora.app
- Your
client_idandclient_secretfrom the dashboard
1. Get an Access Token¶
TOKEN=$(curl -s -X POST https://auth.invora.app/oauth/v2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&scope=openid" \
| jq -r '.access_token')
All subsequent requests include Authorization: Bearer $TOKEN.
2. Complete Business Profile¶
First-time setup — creates your organization and activates a free trial:
curl -X POST https://gateway.invora.app/api/identity/v2/registration/complete-profile \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"businessName": "Acme Trading Co.",
"country": "SA",
"capabilities": ["BUSINESS_CAPABILITY_EINVOICING"]
}'
Response includes your tenantId and M2M credentials (clientId, clientSecret) for API automation.
3. Configure Your Business Identity¶
Set your legal name, address, and tax ID — this appears as the supplier on every document:
curl -X PUT https://gateway.invora.app/api/v2/settings/self-party \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"mask": "myInfo.party",
"myInfo": {
"party": {
"partyName": [{"name": {"value": "Acme Trading Co."}}],
"postalAddress": {
"streetName": {"value": "King Fahd Road"},
"cityName": {"value": "Riyadh"},
"postalZone": {"value": "12345"},
"country": {"identificationCode": {"value": "SA"}}
},
"partyTaxScheme": [{
"companyId": {"value": "300000000000003"},
"taxScheme": {"id": {"value": "VAT"}}
}],
"partyLegalEntity": [{
"registrationName": {"value": "Acme Trading Co. Ltd."},
"companyId": {"value": "7001234567"}
}]
}
}
}'
4. Add a Customer¶
curl -X POST https://gateway.invora.app/api/v2/parties \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"changes": {
"name": {"values": [{"locale": "en", "value": "Beta Corp"}]},
"role": "PARTY_ROLE_CUSTOMER",
"details": {
"partyName": [{"name": {"value": "Beta Corp"}}],
"postalAddress": {
"streetName": {"value": "Olaya Street"},
"cityName": {"value": "Jeddah"},
"country": {"identificationCode": {"value": "SA"}}
},
"partyTaxScheme": [{
"companyId": {"value": "300000000000004"},
"taxScheme": {"id": {"value": "VAT"}}
}]
}
}
}'
Note the returned key — you'll reference the customer's party details in the invoice UBL content.
5. Create and Freeze an Invoice¶
curl -X POST https://gateway.invora.app/api/v2/documents \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"freezeImmediately": true,
"changes": {
"content": {
"invoice": {
"id": {"value": "INV-001"},
"issueDate": {"value": "2026-04-29"},
"invoiceTypeCode": {"value": "388"},
"documentCurrencyCode": {"value": "SAR"},
"accountingSupplierParty": {
"party": {
"partyName": [{"name": {"value": "Acme Trading Co."}}],
"partyTaxScheme": [{
"companyId": {"value": "300000000000003"},
"taxScheme": {"id": {"value": "VAT"}}
}]
}
},
"accountingCustomerParty": {
"party": {
"partyName": [{"name": {"value": "Beta Corp"}}],
"partyTaxScheme": [{
"companyId": {"value": "300000000000004"},
"taxScheme": {"id": {"value": "VAT"}}
}]
}
},
"legalMonetaryTotal": {
"lineExtensionAmount": {"value": "1000.00", "currencyId": {"value": "SAR"}},
"taxExclusiveAmount": {"value": "1000.00", "currencyId": {"value": "SAR"}},
"taxInclusiveAmount": {"value": "1150.00", "currencyId": {"value": "SAR"}},
"payableAmount": {"value": "1150.00", "currencyId": {"value": "SAR"}}
},
"taxTotal": [{
"taxAmount": {"value": "150.00", "currencyId": {"value": "SAR"}},
"taxSubtotal": [{
"taxableAmount": {"value": "1000.00", "currencyId": {"value": "SAR"}},
"taxAmount": {"value": "150.00", "currencyId": {"value": "SAR"}},
"taxCategory": {
"id": {"value": "S"},
"percent": {"value": "15.00"},
"taxScheme": {"id": {"value": "VAT"}}
}
}]
}],
"invoiceLine": [{
"id": {"value": "1"},
"invoicedQuantity": {"value": "10.00", "unitCode": {"value": "EA"}},
"lineExtensionAmount": {"value": "1000.00", "currencyId": {"value": "SAR"}},
"item": {
"name": {"value": "Widget"},
"classifiedTaxCategory": [{
"id": {"value": "S"},
"percent": {"value": "15.00"},
"taxScheme": {"id": {"value": "VAT"}}
}]
},
"price": {
"priceAmount": {"value": "100.00", "currencyId": {"value": "SAR"}}
}
}]
}
}
}
}'
With freezeImmediately: true, this single call:
1. Creates the invoice in draft state
2. Validates against business rules
3. Freezes (locks) the document — editState becomes EDIT_STATE_FROZEN
4. Runs the regulation pipeline (ZATCA signing + submission, if enabled)
5. Returns the complete document, including regulationMetadata — per-regulation submission status, diagnostics, and artifacts (the ZATCA QR code is an artifact under regulationMetadata.entries["zatca"])
6. Generate a PDF¶
curl -X POST https://gateway.invora.app/api/v2/pdf/generate \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"documentKey": "INV-001",
"documentType": "DOCUMENT_TYPE_INVOICE",
"config": {
"showLogo": true,
"showQrCode": true,
"showStamp": true,
"showSignature": true
}
}'
Response includes a downloadUrl for the branded PDF.
7. Send to Customer¶
curl -X POST https://gateway.invora.app/api/v2/documents/INV-001/send \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"concurrencyStamp": "<stamp-from-create-response>"}'
Records that the frozen document was delivered and notifies the recipient.
What's Next¶
- Validate before freezing:
POST /api/v2/documents/{key}/validate - Preview PDF without saving:
POST /api/v2/pdf/previewwith inline UBL content - Bulk operations:
POST /api/v2/documents/bulk-createfor batch import - Real-time updates: Use gRPC
ListStream/GetStreamfor live document feeds - ZATCA onboarding: See ZATCA Guide for e-invoicing compliance
- Billing setup: See Billing API Guide for subscriptions and usage metering
- Connected businesses: See Identity API Guide for multi-tenant platform setup
API Flow Diagram¶
flowchart TD
subgraph Registration
A[Complete business profile] --> B[Select plan]
B --> C[Trial active]
end
subgraph Setup
D[Update self-party] --> E[Update settings]
E --> F[Create party]
end
subgraph Operations
G[Create draft] --> H[Validate<br/>optional]
H --> I[Freeze<br/>regulation pipeline]
I --> J[Send]
J --> K[Generate PDF]
end
Registration --> Setup
Setup --> Operations