Skip to main content

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/sessions or POST /v1/sessions-profile, then call POST /v1/sessions/{session_id}/pay to 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

FieldTypeRequiredDescription
payment_product_typeStringYes"kravia.invoice_b2b", "kravia.invoice_b2b_grouped", or "kravia.invoice_b2c"
operationStringYesMust be "invoice_payment"
days_until_dueIntegerYesDays until invoice is due (0-365)
invoice_channelStringNo"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

FieldTypeRequiredDescription
payment_product_typeStringYes"kravia.invoice_b2b", "kravia.invoice_b2b_grouped", or "kravia.invoice_b2c"
billing_addressObjectYesCustomer 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:

ToggleBehavior
strict-merchant-referenceReturns 400 if merchant_reference already exists in any session
strict-success-merchant-referenceReturns 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