Merchant Initiated Payments
You can create and pay invoices programmatically without the customer going through checkout. There are two approaches depending on your use case:
- One-step: use the Merchant Initiate Transaction (MIT) endpoint
POST /v1/sessions/pay. Best for automated invoicing or recurring billing. - Two-step: create a session via
POST /v1/sessionsorPOST /v1/sessions-profile, then callPOST /v1/sessions/{session_id}/payto complete it. Useful when you want to set up the session first and pay it later, or when integrating with existing session creation flows.
Billing Address Requirements
Both flows require a billing address with the same fields as customer checkout. The location differs: in one-step it's in session.order.billing_address, in two-step it's in the pay request body.
One-Step: Create and Pay
A single call creates the session and registers the invoice:
Identity verification is automatically skipped. The billing address is provided in session.order.billing_address (see required fields).
B2B Example
POST /v1/sessions/pay
Authorization: Bearer <token>
Content-Type: application/json
{
"payment": {
"payment_product_type": "kravia.invoice_b2b",
"operation": "invoice_payment",
"days_until_due": 30
},
"session": {
"url": {
"callback_url": "https://example.com/callback"
},
"order": {
"amount": 29900,
"currency": "NOK",
"vat_amount": 5980,
"merchant_reference": "<your-unique-id-here>",
"items": [
{
"description": "Monthly subscription - Premium",
"quantity": 1,
"amount": 29900,
"vat": 25,
"line_id": "sub-001"
}
],
"billing_address": {
"first_name": "Ola",
"last_name": "Nordmann",
"business_name": "Nordmann AS",
"organization_number": "123456789",
"email": "ola@nordmann.no",
"phone_number": "+4799999999",
"address_line": "Storgata 1",
"postal_code": "0151",
"postal_place": "Oslo",
"country": "NO"
}
}
}
}
B2C Example
For B2C invoices, omit business_name and organization_number:
POST /v1/sessions/pay
Authorization: Bearer <token>
Content-Type: application/json
{
"payment": {
"payment_product_type": "kravia.invoice_b2c",
"operation": "invoice_payment",
"days_until_due": 14
},
"session": {
"url": {
"callback_url": "https://example.com/callback"
},
"order": {
"amount": 29900,
"currency": "NOK",
"vat_amount": 5980,
"merchant_reference": "<your-unique-id-here>",
"items": [
{
"description": "Online subscription",
"quantity": 1,
"amount": 29900,
"vat": 25,
"line_id": "item-1"
}
],
"billing_address": {
"first_name": "Kari",
"last_name": "Nordmann",
"email": "kari@example.no",
"phone_number": "+4798765432",
"address_line": "Lillegata 5",
"postal_code": "5003",
"postal_place": "Bergen",
"country": "NO"
}
}
}
}
One-Step Payment Fields
| Field | Type | Required | Description |
|---|---|---|---|
payment_product_type | String | Yes | "kravia.invoice_b2b", "kravia.invoice_b2b_grouped", or "kravia.invoice_b2c" |
operation | String | Yes | Must be "invoice_payment" |
days_until_due | Integer | Yes | Days until invoice is due (0-365) |
invoice_channel | String | No | "kravia" (default) or "merchant". See Invoice Delivery. |
Two-Step: Create Session, Then Pay
Create a session first, then programmatically call the pay endpoint. We recommend setting require_identity_verification: false on the payment type configuration to skip identity verification.
Step 1: Create the Session
For B2B
POST /v1/sessions
Authorization: Bearer <token>
Content-Type: application/json
{
"url": {
"callback_url": "https://example.com/callback"
},
"order": {
"amount": 29900,
"currency": "NOK",
"vat_amount": 5980,
"merchant_reference": "<your-unique-id-here>",
"items": [
{
"description": "Consulting services",
"quantity": 1,
"amount": 29900,
"vat": 25,
"line_id": "item-1"
}
]
},
"configuration": {
"kravia": {
"type": "payment_type",
"invoice_b2b": {
"type": "payment_product_type",
"enabled": true,
"days_until_due": 30,
"require_identity_verification": false,
"invoice_channel": "kravia"
}
}
}
}
For B2C, set the same flags:
{
"configuration": {
"kravia": {
"type": "payment_type",
"invoice_b2c": {
"type": "payment_product_type",
"enabled": true,
"days_until_due": 14,
"require_identity_verification": false,
"invoice_channel": "kravia"
}
}
}
}
Step 2: Pay the Session
Call the pay endpoint with the payment_product_type and billing_address. Note that the billing address is provided in the pay request body, not in the session order:
B2B:
POST /v1/sessions/{session_id}/pay
Authorization: Bearer <token>
Content-Type: application/json
{
"payment_product_type": "kravia.invoice_b2b",
"billing_address": {
"first_name": "Ola",
"last_name": "Nordmann",
"business_name": "Nordmann AS",
"organization_number": "123456789",
"email": "ola@nordmann.no",
"phone_number": "+4799999999",
"address_line": "Storgata 1",
"postal_code": "0151",
"postal_place": "Oslo",
"country": "NO"
}
}
B2C:
POST /v1/sessions/{session_id}/pay
Authorization: Bearer <token>
Content-Type: application/json
{
"payment_product_type": "kravia.invoice_b2c",
"billing_address": {
"first_name": "Kari",
"last_name": "Nordmann",
"email": "kari@example.no",
"phone_number": "+4798765432",
"address_line": "Lillegata 5",
"postal_code": "5003",
"postal_place": "Bergen",
"country": "NO"
}
}
Two-Step Pay Fields
| Field | Type | Required | Description |
|---|---|---|---|
payment_product_type | String | Yes | "kravia.invoice_b2b", "kravia.invoice_b2b_grouped", or "kravia.invoice_b2c" |
billing_address | Object | Yes | Customer billing details, see billing address requirements |
Response
Both approaches return a transaction with status CAPTURED:
{
"id": "T12345",
"status": "CAPTURED",
"payment_product_type": "kravia.invoice_b2b",
"amount": 29900,
"merchant_reference": "inv-2026-001",
"metadata": {
"kravia:invoice_number": "INV-2026-0001",
"kravia:invoice_url": "https://api.dintero.com/v1/files/f-abc123"
},
"events": [
{
"name": "CAPTURE",
"created_at": "2026-01-15T10:30:00Z",
"metadata": {
"kravia:invoice_date": "2026-01-15",
"kravia:invoice_due_date": "2026-02-14",
"kravia:invoice_number": "INV-2026-0001"
}
}
]
}
Duplicate Prevention
Use the Dintero-Feature-Toggles header to prevent duplicate invoices:
| Toggle | Behavior |
|---|---|
strict-merchant-reference | Returns 400 if merchant_reference already exists in any session |
strict-success-merchant-reference | Returns 400 if merchant_reference exists in a successfully authorized session. Allows retries after failures. |
POST /v1/sessions/pay
Authorization: Bearer <token>
Dintero-Feature-Toggles: strict-success-merchant-reference
Content-Type: application/json
{ ... }
See Also
- Customer Checkout: customer selects invoice at checkout
- Grouped Invoices: consolidate multiple purchases into a single invoice
- Invoice Delivery: control who delivers the invoice