GenerateSEPA: Technical API Documentation

2026-06-14

You’re usually not starting from a blank slate. You already have payment data in an ERP, an accounting tool, a CSV export, or a legacy AEB workflow. The problem starts when that data has to become valid SEPA XML without manual cleanup, repeated bank rejections, or a finance team asking why one field that looked optional turned out to be mandatory.

That’s where technical API documentation often fails. It tells a developer which endpoint accepts a payload, but it doesn’t explain why a missing mandate reference matters, why sequence type changes the meaning of a direct debit, or why an IBAN that looks plausible can still trigger downstream rejection fees. In finance workflows, syntax is only half the job.

Good technical API documentation has to connect the request body to the business event. That matters because clear, interactive docs can cut onboarding time by up to 50% and reduce support ticket volume by 30 to 40%, according to the cited industry summary of the 2023 Software Engineering Institute report in this reference. In practice, that means fewer failed test cycles and fewer conversations between developers and finance admins trying to decode what the API “really wants.”

Introduction and Getting Started

Manual SEPA file generation usually breaks in familiar places. An export has the wrong date format. A creditor account is valid internally but not valid for the bank. A finance user enters the payment concept the way it appears on an invoice, but the bank file expects stricter structure. When those problems are handled by spreadsheet edits and last-minute XML inspection, the process becomes slow and fragile.

The API approach is simpler. Your system sends JSON, the service validates the data, and the output is a bank-ready SEPA XML file for direct debits or credit transfers. That removes the step where someone has to manually transform operational data into an XML structure that most business users should never have to touch.

What the API is for

At a practical level, the API handles three jobs:

  • Data intake: your application submits remittance data in JSON.
  • Compliance-oriented transformation: the service maps that data into the correct SEPA structure.
  • File delivery: your system receives access to the generated XML so it can hand it to the bank workflow.

If you want a quick external refresher on what separates reference docs from useful onboarding, DocuWriter.ai’s API documentation guide is a solid companion read. It’s helpful when you’re designing internal integration notes for both developers and finance stakeholders.

Your first required step

Authentication comes first. Access is controlled with an API key, and you obtain that key from your account dashboard. If you’re checking platform availability or confirming that an API is the right integration path, the product help page on using the API from your own system is the right place to start.

Practical rule: Treat the API key as production credential material from day one, even during testing. Most integration problems start because teams treat the first test key like throwaway data and then copy the same habits into production.

Base URL and first-call mindset

Use a single base URL for all requests:

https://api.generatesepa.com

Your first successful call should aim for one narrow outcome: submit a minimal but valid remittance and confirm that you receive a created response plus a file retrieval path. Don’t start by modeling every internal edge case from your ERP. Start with one creditor, one debtor, one amount, one execution date, and one clear remittance concept. In finance APIs, small valid payloads teach more than large “realistic” payloads that fail in six places at once.

Core Concepts and API Workflow

Teams often think they’re integrating a file generator. They’re not. They’re integrating a payment workflow with regulatory and banking assumptions embedded in it. That difference matters because a JSON field only makes sense when you know what financial responsibility it represents.

Recent analysis cited by Speakeasy reports that 65% of implementation failures for finance APIs stem from non-developers misinterpreting the API’s business purpose rather than its syntax, which is why business-context-first docs matter in this domain, as noted in Speakeasy’s documentation analysis.

A diagram illustrating the five-step SEPA Remittance API workflow from initial request to final confirmation.

The remittance object

The core object is the remittance. Think of it as the business container for a batch of transactions that belong together operationally and financially. A remittance isn’t just an array of payments. It carries the context that tells the bank who is initiating the collection or transfer, under which identifiers, and under which rules.

A typical remittance contains:

  • Creditor or sender data: the legal entity initiating the transfer or collection.
  • Execution context: when the bank should process the remittance.
  • Transaction lines: the individual debtors or recipients.
  • Scheme identifiers: fields that connect the request to SEPA-specific requirements.

Why the SEPA fields exist

Several fields cause confusion because they look administrative rather than technical. They aren’t optional in practice.

  • Creditor ID: identifies the party collecting direct debits. Without it, a direct debit instruction may be structurally incomplete for the intended use case.
  • Mandate ID: links a debit to the signed authorization from the debtor. Finance teams often understand this before developers do, which is why the field needs plain-language explanation in the docs.
  • Sequence type: values such as FRST and RCUR tell the bank whether a debit is the first in a mandate series or a recurring collection. Choosing the wrong one isn’t a formatting bug. It changes the business meaning of the payment instruction.

A developer sees strings in JSON. A finance team sees legal and banking traceability. Good technical API documentation has to serve both readings.

The workflow in practice

The actual workflow is straightforward once you separate the steps:

  1. Your system sends JSON with remittance metadata and transaction lines.
  2. The API validates business-critical fields such as identifiers, date formats, and account data.
  3. The service converts the request into SEPA XML using the appropriate structure for the remittance type.
  4. Your system receives a result that confirms processing and provides access to the generated file.
  5. The finance process continues with download, review if needed, and bank submission.

If you want a broader implementation view focused on the JSON-to-SEPA transformation itself, the article on SEPA XML API workflows gives useful platform-specific context.

A clean integration happens when developers and finance admins can both answer the same question: what business event does this payload represent?

Authentication and Security Protocols

API authentication uses the Bearer scheme in the Authorization header. Keep it plain and predictable. If the header is wrong, every other part of the request is irrelevant.

Header format

Use this exact pattern:

Authorization: Bearer YOUR_API_KEY

A minimal HTTP example looks like this:

POST /v1/remittances HTTP/1.1
Host: api.generatesepa.com
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

How to store the key

Hardcoding the key into source files is the fastest way to create a cleanup job later. Store it in an environment variable and read it at runtime from your application config.

Recommended handling:

  • Local development: keep the key in a local environment file that isn’t committed.
  • Shared environments: inject the key through your deployment platform’s secret manager.
  • Rotations: design your application so the key can be replaced without code changes.
  • Logging: never print the full key in application logs, exception traces, or support screenshots.

Security model around the request

All data in transit is encrypted with TLS 1.2+. That matters because remittance payloads contain bank-account and payment-instruction data that should never move over an unprotected channel.

The second control is lifecycle-based rather than transport-based. Customer remittance data is automatically deleted from servers 10 minutes after processing. That same short retention window applies to the generated file access lifecycle, which is why your integration should retrieve the output promptly instead of assuming it will remain available indefinitely.

For teams reviewing vendor posture before rollout, the article on online payment security practices is worth sharing with security and finance stakeholders.

What works in production

A secure integration usually has three traits:

  • Single-purpose credentials: one key per environment, not one key copied across everything.
  • Short path from request to retrieval: submit, confirm, download, and store the resulting file in your own controlled system.
  • No credential leakage into support loops: when an integration fails, log request IDs and validation errors, not secrets.

What doesn’t work is treating financial API authentication like a generic internal utility. The implications are more significant because the payloads have payment consequences.

Endpoint Reference Remittance Creation

The primary endpoint for file generation is:

POST /v1/remittances

This endpoint accepts a JSON payload describing the remittance and returns a created response when the request passes validation and the XML is generated successfully.

A person coding a financial remittance API request on a laptop computer at a wooden table.

Request body example

Use realistic values in development. That matters in finance integrations because placeholder examples often hide the exact constraints that will break a bank submission. Speakeasy’s cited 2025 study says 42% of API integration errors in financial sectors occur because examples use placeholder values that don’t reflect real banking constraints, as summarized in this Gravitee guide discussion.

{
  "type": "direct_debit",
  "execution_date": "2026-06-30",
  "creditor_name": "Acme Services S.L.",
  "creditor_iban": "ES9121000418450200051332",
  "creditor_id": "ES98ZZZ123456789",
  "currency": "EUR",
  "sequence_type": "FRST",
  "transactions": [
    {
      "debtor_name": "Laura Martin",
      "debtor_iban": "ES7921000813610123456789",
      "amount": 125.50,
      "concept": "Invoice INV-2026-0042",
      "mandate_id": "MANDATE-00045",
      "mandate_signature_date": "2025-12-15",
      "end_to_end_id": "INV-2026-0042"
    }
  ]
}

Field reference

Field Type Required Description
type string Yes Remittance type, such as direct debit or credit transfer
execution_date string Yes Processing date in ISO 8601 date format
creditor_name string Yes Legal or operational name of the initiating party
creditor_iban string Yes IBAN of the account that sends or collects funds
creditor_id string Required for direct debit SEPA creditor identifier
currency string Yes Currency code. Use EUR for SEPA remittances
sequence_type string Required for direct debit Debit sequence such as FRST or RCUR
transactions array Yes List of payment or debit instructions

Transaction object

Each item in transactions supports the following fields:

  • debtor_name: string, required for direct debit. Name associated with the debtor account.
  • debtor_iban: string, required. Bank account in IBAN format.
  • amount: number, required. Monetary amount for the transaction.
  • concept: string, required. Human-readable remittance description.
  • mandate_id: string, required for direct debit. Reference to the debtor mandate.
  • mandate_signature_date: string, required for direct debit. ISO 8601 date.
  • end_to_end_id: string, optional but recommended. Tracking identifier that helps reconciliation.

Validation rules that matter

It is within business context that expensive mistakes are prevented.

  • Dates must use ISO 8601. Use YYYY-MM-DD. Don’t send locale-specific dates like 30/06/2026.
  • IBAN values are validated for country code structure, expected length, and checksum logic. An account that “looks right” to a user may still fail validation.
  • Concept text should stay concise and bank-safe. Don’t treat it like a free-form note field from your CRM.
  • Sequence type must match mandate state. FRST and RCUR are not interchangeable labels.
  • Currency should align with the SEPA scheme. For standard SEPA flows, use EUR.

Implementation note: Validate your JSON before sending it, but don’t duplicate every bank rule in your own application. Keep client-side validation focused on obvious formatting errors and let the API remain the authority for SEPA-specific checks.

Mapping legacy AEB formats

If your source data comes from older Spanish banking files, the API layer should become your translation point, not your business logic layer. Typical legacy imports such as AEB 34, 14, and 59 should be mapped into the remittance JSON structure before submission.

A practical mapping approach looks like this:

  • Origin account data maps to creditor_iban and related remittance-level fields.
  • Payer or beneficiary records map into transactions.
  • Legacy reference numbers often belong in mandate_id or end_to_end_id, depending on their actual accounting role.
  • Collection type indicators usually map to sequence_type for direct debit workflows.

If your team is migrating from a legacy export, don’t start by recreating the old file line by line in code. Start by identifying what each field means in payment operations, then map that meaning into the API schema.

Understanding API Responses

A successful creation request returns 201 Created and a JSON body with the information your application needs to continue the workflow. The response should be treated as operational output, not just confirmation text.

Example success response

{
  "remittance_id": "rem_8f3c2a91",
  "status": "completed",
  "download_url": "https://api.generatesepa.com/downloads/rem_8f3c2a91.xml",
  "expires_at": "2026-06-25T10:25:00Z"
}

What each field means

Field Meaning How to use it
remittance_id Unique identifier for the generated remittance Store it in logs, reconciliation records, and support tickets
status Processing outcome Confirm that the XML is ready before attempting retrieval
download_url Temporary secure link to the generated file Fetch the XML immediately and store it in your system
expires_at Expiration time for the file access window Use it to avoid trying to retrieve an expired artifact

The file retrieval lifecycle

The most important field is download_url. It’s the handoff point between API processing and your banking workflow. Once you receive it, your application should retrieve the XML and place it where your finance team or downstream automation expects it.

The URL is temporary by design. It expires after 10 minutes, which aligns with the short data-retention model described earlier. Don’t build integrations that depend on reopening old links from historical logs. Persist the XML in your own secured storage if you need longer retention for audit or operational reasons.

Retrieve first, reconcile second. If you reverse that order, a valid remittance can become an avoidable retrieval failure.

What a mature client does after success

A production client usually performs these steps immediately after the 201 Created response:

  1. Store remittance_id with the originating internal batch ID.
  2. Check that status indicates completion.
  3. Download the XML from download_url.
  4. Save the file in your own storage or hand it to the next internal process.
  5. Record the retrieval outcome for auditability.

Don’t treat the response body as something a developer glances at during testing and then ignores in production. In financial integrations, the response is part of the business trail.

Error Handling and Reference Codes

Errors need to help the caller recover. A vague "failed" response may be acceptable in an internal prototype. It’s not acceptable in finance-facing technical API documentation where the caller has to decide whether to retry, correct data, or escalate.

The standard structure should include an HTTP status code plus a machine-readable error_code and a human-readable error_message. That aligns with the cited guidance summarized from GOV.UK API standards in this reference on structured error handling.

Standard error shape

A typical error body should look like this:

{
  "error_code": "INVALID_IBAN",
  "error_message": "The debtor_iban field failed IBAN validation.",
  "details": {
    "field": "transactions[0].debtor_iban"
  }
}

This format does three jobs at once:

  • it gives application code a stable value to branch on
  • it gives developers a readable diagnosis
  • it points to the field that needs attention

API Error Code Reference

HTTP Status Error Code Description Suggested Action
400 INVALID_REQUEST Request body is malformed or missing required fields Validate JSON structure and required fields before resubmitting
400 INVALID_IBAN One of the IBAN fields failed validation Check country code, length, and checksum input
400 INVALID_DATE_FORMAT A date field does not use the expected format Send dates in ISO 8601 format such as YYYY-MM-DD
400 INVALID_SEQUENCE_TYPE Sequence type is incompatible with the remittance context Confirm whether the mandate should be first or recurring
401 UNAUTHORIZED API key is missing, expired, or invalid Verify the Authorization: Bearer header and key source
429 RATE_LIMITED Too many requests were sent in a short period Slow the request rate and retry according to your backoff policy
500 INTERNAL_ERROR The service failed while processing a valid request Retry if appropriate and log the request context for support

How to respond to errors

Different errors require different behavior.

  • Validation errors should stop the workflow and return a correction task to the calling system or operations user.
  • Authentication errors should trigger configuration checks, not blind retries.
  • Rate-limit responses should invoke a retry strategy with spacing between attempts.
  • Server-side failures should be logged with the request metadata that helps support reproduce the issue, but never with exposed credentials.

If an error response can’t tell the developer what to fix next, it’s not finished documentation.

Practical Integration Examples

Working code closes the gap between understanding the schema and proving that the integration works. The examples below aren’t toy snippets. They include authentication, a realistic request body, success handling, and basic failure handling.

A male programmer working on Python API code examples displayed across dual computer monitors at his desk.

cURL example

Use cURL for the first live test because it removes application complexity and lets you verify the API contract directly.

curl -X POST "https://api.generatesepa.com/v1/remittances" \
  -H "Authorization: Bearer $GENERATESEPA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "direct_debit",
    "execution_date": "2026-06-30",
    "creditor_name": "Acme Services S.L.",
    "creditor_iban": "ES9121000418450200051332",
    "creditor_id": "ES98ZZZ123456789",
    "currency": "EUR",
    "sequence_type": "FRST",
    "transactions": [
      {
        "debtor_name": "Laura Martin",
        "debtor_iban": "ES7921000813610123456789",
        "amount": 125.50,
        "concept": "Invoice INV-2026-0042",
        "mandate_id": "MANDATE-00045",
        "mandate_signature_date": "2025-12-15",
        "end_to_end_id": "INV-2026-0042"
      }
    ]
  }'

If the call succeeds, capture the download_url and test retrieval immediately. If it fails, inspect the error_code first. Don’t start debugging raw JSON formatting until you’ve read the error payload.

JavaScript example

For Node.js, keep the client explicit. Read the key from the environment, build the payload clearly, and surface both success and failure output.

If you’re building the surrounding app quickly, this guide on shipping apps with AI is useful for scaffolding the non-payment parts faster while keeping the payment integration itself deliberate and reviewable.

import axios from "axios";

const apiKey = process.env.GENERATESEPA_API_KEY;

const payload = {
  type: "direct_debit",
  execution_date: "2026-06-30",
  creditor_name: "Acme Services S.L.",
  creditor_iban: "ES9121000418450200051332",
  creditor_id: "ES98ZZZ123456789",
  currency: "EUR",
  sequence_type: "FRST",
  transactions: [
    {
      debtor_name: "Laura Martin",
      debtor_iban: "ES7921000813610123456789",
      amount: 125.5,
      concept: "Invoice INV-2026-0042",
      mandate_id: "MANDATE-00045",
      mandate_signature_date: "2025-12-15",
      end_to_end_id: "INV-2026-0042"
    }
  ]
};

async function createRemittance() {
  try {
    const response = await axios.post(
      "https://api.generatesepa.com/v1/remittances",
      payload,
      {
        headers: {
          Authorization: `Bearer ${apiKey}`,
          "Content-Type": "application/json"
        }
      }
    );

    console.log("Remittance created:", response.data.remittance_id);
    console.log("Status:", response.data.status);
    console.log("Download URL:", response.data.download_url);
  } catch (error) {
    if (error.response) {
      console.error("HTTP status:", error.response.status);
      console.error("Error code:", error.response.data.error_code);
      console.error("Message:", error.response.data.error_message);
    } else {
      console.error("Request failed:", error.message);
    }
  }
}

createRemittance();

For a platform-specific walkthrough in the same runtime, the help article on integrating the SEPA API in Node is the right next step.

A short visual walkthrough can also help when you’re validating the sequence from request creation to result handling:

Python example

Python is often the cleanest fit for back-office automation, scheduled jobs, and finance-oriented middleware.

import os
import requests

api_key = os.environ.get("GENERATESEPA_API_KEY")

payload = {
    "type": "direct_debit",
    "execution_date": "2026-06-30",
    "creditor_name": "Acme Services S.L.",
    "creditor_iban": "ES9121000418450200051332",
    "creditor_id": "ES98ZZZ123456789",
    "currency": "EUR",
    "sequence_type": "FRST",
    "transactions": [
        {
            "debtor_name": "Laura Martin",
            "debtor_iban": "ES7921000813610123456789",
            "amount": 125.50,
            "concept": "Invoice INV-2026-0042",
            "mandate_id": "MANDATE-00045",
            "mandate_signature_date": "2025-12-15",
            "end_to_end_id": "INV-2026-0042"
        }
    ]
}

headers = {
    "Authorization": f"Bearer {api_key}",
    "Content-Type": "application/json"
}

response = requests.post(
    "https://api.generatesepa.com/v1/remittances",
    json=payload,
    headers=headers,
    timeout=30
)

if response.status_code == 201:
    data = response.json()
    print("Remittance created:", data["remittance_id"])
    print("Status:", data["status"])
    print("Download URL:", data["download_url"])
else:
    try:
        error = response.json()
        print("HTTP status:", response.status_code)
        print("Error code:", error.get("error_code"))
        print("Message:", error.get("error_message"))
    except ValueError:
        print("HTTP status:", response.status_code)
        print("Non-JSON error response:", response.text)

What these examples deliberately include

  • Environment-variable credentials instead of inline secrets
  • A realistic direct debit payload instead of placeholders
  • Success-path output that exposes the identifiers you need
  • Basic error inspection that reads the structured error body

That’s the standard for useful technical API documentation. A code example should survive first contact with a real integration.

Rate Limits SLAs and Best Practices

Production integrations fail less often when the operational rules are documented as clearly as the endpoint schema. That includes request pacing, availability expectations, and change management.

The platform provides 99.9% availability and uses a versioned API model under /v1/, which gives clients a stable integration target while allowing future evolution. Versioning should remain explicit in both the path and the changelog. Best-practice guidance summarized from industry tooling recommendations also supports OpenAPI specifications, detailed changelogs, and organization by developer workflows rather than alphabetical endpoint lists, as noted in this overview of API documentation best practices.

Production habits that reduce support work

  • Respect rate limiting: your client should recognize 429 responses and retry with backoff instead of hammering the endpoint.
  • Design for idempotency on your side: if your job runner retries after a timeout, make sure you can detect whether the remittance was already created.
  • Store correlation data: keep your own batch ID linked to the returned remittance_id.
  • Watch changelogs before deployments: versioned APIs are only useful if your release process checks what changed.

What stable integrations usually look like

A reliable client isn’t the one with the most abstraction. It’s the one that behaves predictably under failure.

That usually means:

  • one clear request builder for remittance payloads
  • one response handler for success and download retrieval
  • one shared error parser
  • one retry policy for transient failures, not for validation errors

Stability comes from consistency. The same payload rules, the same logging rules, and the same retry rules should apply in every environment.

If your finance team depends on daily remittance generation, don’t treat the API integration as a side utility. Treat it like a payment pipeline with explicit operational ownership.


If you want to stop hand-building SEPA files and move to a validated JSON-to-XML workflow, GenerateSEPA gives technical teams and finance departments a practical way to automate remittances, support legacy banking formats, and produce bank-ready SEPA XML without maintaining the conversion logic themselves.


Frequently Asked Questions

What does the GenerateSEPA API do?
The GenerateSEPA API accepts a JSON payload describing a remittance, validates the data against SEPA rules, and returns a bank-ready SEPA XML file. It handles both direct debits and credit transfers, removing the need to manually build or inspect XML.
How do I authenticate with the GenerateSEPA API?
Authentication uses the Bearer scheme in the Authorization header: Authorization: Bearer YOUR_API_KEY. Obtain the key from your account dashboard and store it in an environment variable rather than in source code. Treat the key as production credential material from the first day of integration, even during testing.
What are the most important SEPA fields in the API request?
For direct debits, the mandatory fields beyond basic creditor and transaction data are creditor_id (the SEPA creditor identifier), mandate_id (linking the debit to a signed authorization), and sequence_type (FRST for first debit, RCUR for recurring). Getting these wrong changes the legal meaning of the payment instruction, not just its formatting.
How long is the generated SEPA XML file available after creation?
The download URL expires after 10 minutes, and customer remittance data is automatically deleted from servers after processing. Retrieve the XML immediately after receiving the 201 Created response and store it in your own secured system. Do not build integrations that depend on reopening old download links from historical logs.

Related posts