Introduction

The objective of this guide is to take you through the process of generating an invoice you can send to your customers. Invopop is very flexible, so for this example we assuming the following conditions:

  • We’re in Spain, although the steps are essentially the same anywhere.

  • We have the basic information about the invoice: date, supplier, customer, items, and the tax type to apply to each.

  • Our invoices do not already have a sequential code, but we want one that looks like TEST-2201001.

  • Customers require an Electronic invoice alongside a PDF.

  • We want an email copy of our invoice.

You don’t need to be a developer to use this guide, but you will need to have a bit of experience using the command line and know how to create a text file. For sending requests to the server we use the “curl” command, included with most operating systems. You might however find it easier to use a visual tool for sending HTTP requests like Postman.

We assume here that you’ve already followed the steps in the Authentication guide, and have an access token ready to use.

To give you a heads up, these are the stages we’ll be going through:

  • Create a new series

  • Build a new workflow with a set of steps to execute

  • Upload a document

  • Create a Job

  • Extract the results

Let’s get started.

Define a Series

Most tax jurisdictions require invoices to contain a sequential or consecutive code that allows inspectors to visually confirm the order of your invoices and check for any gaps. Some countries take this very seriously, and may impose penalities if not done properly.

Generating sequential numbers reliably, especially in a distributed system, is actually quite a tough technical challenge. Fortunately at Invopop we’ve tried to hide away the complexity with a simple interface.

Inside the Invopop Console:

  1. Enter the Series section on the side menu.

  2. Tap the ”New Series” button.

  3. In Name enter “Test Series”.

  4. In Code enter “TEST”.

  5. In Prefix enter “22”.

  6. In Padding, leave as 5.

  7. In Start Number, enter 1000.

  8. Notice that the Preview box shows TEST-2201000, and tap the ”Save” button.

  9. The new series should now appear in the list.

In the next section, we’ll figure out how to use this new sequence inside an integration.

Define a Workflow

A Workflow in Invopop is essentially a list of steps that will be executed one-by-one for an incoming job. Each step is linked with a provider of a given service, like generating a PDF, forwarding invoices to an external tax agency, sending emails, or posting webhooks.

  1. Head to the Workflows section.

  2. Tap ”New Workflow

  3. Use the Name field to give this new workflow an easy way to be identified, like “Process Invoice”.

  4. In the steps section, tap the ”+” button. You’ll need to repeat this step for the sections described below:

    • Series, to assign a sequential code to an invoice,
    • FacturaE, for the Electronic invoice format used in Spain,
    • PDF Generator, and,
    • Send to Email.
  5. Once all the steps are added, tap the ”Save” button at the top.

Congratulations! you just created a new workflow! Notice the ”ID:*” field, this is the identifier we’ll need to be able to use this workflow from the terminal or command line.

Add Series Step

Series are used to assign sequential numbers to documents, typically invoice codes, and guarantee their order.

  1. From the list of providers, click Series Enumerator.

  2. The Name should already be set to “Series Enumerator”.

  3. Tap ”Edit configuration“.

  4. In the popup dialog, pick the “Test Series” option representing series we created in the last section.

  5. Check the “Close draft envelopes automatically after adding sequence code” checkbox.

  6. Tap ”Save”, you should see the configuration field is filled in with some JSON.

  7. Tap ”Ok” to add the step to the workflow.

Add FacturaE Step

FacturaE is the Spanish Electronic Invoicing format in XML. NOTE, if you’re not in Spain, you can skip creating this step and move onto the next.

  1. Select FacturaE from the list of providers.

  2. Click ”Edit configuration“.

  3. Read through and check the “Accept Legal Terms and Conditions” checkbox.

  4. Tap ”Save“.

  5. Tap ”OK” to include the step in the workflow.

There should now be a FacturaE step in the list.

Add PDF Generation Step

The Invopop PDF Generator is used to convert GOBL documents into human readable PDF files that can be shared with customers.

  1. Select PDF Generator from the list.

  2. Tap ”Edit configuration“.

  3. Choose a language for the invoices and upload a company logo if you have one to hand. Also select or change any of the settings you think might be relevant for you.

  4. Tap ”Save“.

  5. Tap ”OK” to add the PDF generator step to the workflow.

Add Email Step

It can be useful to send emails to customers or billing departments with details about the invoices that have been generated.

  1. Select the Send to Email provider.

  2. Click ”Edit configuration“.

  3. Introduce a destination in the “To:” or “BCC:” fields by typing the address either in regular or “mailbox” format. (mailbox format includes name, e.g. John Smith <john.smith@example.com>).

  4. Alter any of the other fields that are appropriate for the email.

  5. Tap the “Automatically add invoice customers” checkbox if you’d like to send copies of emails to customers defined in invoices.

  6. Tap ”Save“.

  7. Tap ”OK” to add the email sending step to the workflow.

Having completed all these steps, you should now have 4 complete steps in the workflow.

Upload a Document

We’ve prepared a workflow with a set of integrations to process and convert invoices. Our next step is to upload a document to be processed by the workflow and extract the results.

At Invopop we use GOBL as our base format. It’s been purpose built (by us) to make it easy to create business documents using JSON and contain everything needed to be globally compatible.

If you haven’t had chance to read the GOBL Docs, there are two basic concepts that are important to understand:

  1. A GOBL Object represents a payload; an invoice, message, contact details, or some other unit of business data, defined using a JSON Schema that GOBL understands.

  2. A GOBL Envelope is a wrapper around a GOBL Object that adds meta-data like a digest and digital signatures.

At Invopop, we only ever store GOBL Envelopes. This is important as it means we can verify the contents and ensure no changes have been made. Most interfaces and APIs in Invopop however will automatically wrap GOBL Objects inside Envelopes, so you don’t need to worry about it when uploading, but you will need to take this into account when downloading.

In the next steps we’re going to need a sample partial GOBL Invoice document to upload, here’s one we created earlier:

{
  "$schema": "https://gobl.org/draft-0/bill/invoice",
  "currency": "EUR",
  "issue_date": "2022-03-29",
  "supplier": {
    "tax_id": {
      "country": "ES",
      "code": "B28774008"
    },
    "name": "Biz España S.L.",
    "emails": [
      {
        "addr": "billing@bizspain.es"
      }
    ],
    "addresses": [
      {
        "num": "42",
        "street": "Calle Pradillo",
        "locality": "Madrid",
        "region": "Madrid",
        "code": "28002",
        "country": "ES"
      }
    ]
  },
  "customer": {
    "tax_id": {
      "country": "ES",
      "code": "B33105842"
    },
    "name": "Customer Spain S.L.",
    "emails": [
      {
        "addr": "sam@customer.com"
      }
    ],
    "addresses": [
      {
        "num": "10",
        "street": "Calle Mayor",
        "locality": "Madrid",
        "region": "Madrid",
        "code": "28003",
        "country": "ES"
      }
    ]
  },
  "lines": [
    {
      "quantity": 50,
      "item": {
        "name": "Promotional mug",
        "price": "16.00"
      },
      "taxes": [
        {
          "cat": "VAT",
          "rate": "standard"
        }
      ]
    }
  ]
}

The most important bits of data to take away from this document are the:

  • JSON schema that identifies the GOBL invoice type,

  • currency and issue date,

  • supplier and customer, with their “tax id”, and,

  • lines of items of a given quantity and price to which VAT at a “standard” rate needs to be applied.

Note we used the word partial earlier to describe this document. It’s not a complete and valid GOBL object as it doesn’t contain important details like the invoice code or tax totals. We call these draft documents and there is a specific property in the header of GOBL Envelopes that indicates we’re working with a draft. As we’ll see shortly, once uploaded to Invopop, the API and workflow we created earlier will automatically assign an invoice code and make the required calculations so it can be finalized.

For more details on creating Invoices, see the GOBL Documentation Site. You’ll find more guides there on all the different options and configurations available for invoices, including ways you can build complete GOBL Envelopes with signatures.

Let’s upload this document to the Invopop Silo service:

  1. Copy and paste the JSON above into you favorite text editor.

  2. Save the JSON into a file named invoice.json in a temporary folder you can easily find from the command line (Downloads is usually a safe bet).

  3. Open the Terminal or command line, and enter the temporary directory, e.g. cd ~/Downloads.

  4. Upload the document using the following Curl command:

curl -H "Authorization: Bearer $INVOPOP_TOKEN" -X POST -F data=@invoice.json https://api.invopop.com/silo/v1/entries | jq .

The response back from the server will be similar to the following:

{
  "id": "181ecd5a-f242-11ec-82f1-0242ac150010",
  "created_at": "2022-06-22T15:43:42.814Z",
  "updated_at": "2022-06-22T15:43:42.814Z",
  "env_schema": "https://gobl.org/draft-0/envelope",
  "doc_schema": "https://gobl.org/draft-0/bill/invoice",
  "digest": {
    "alg": "sha256",
    "val": "ca93946485519b3aadf82de2f1654523c98f8afdf90da28ea1d0067a59d1341a"
  },
  "draft": true,
  "data": {
    "$schema": "https://gobl.org/draft-0/envelope",
    "head": {
      "uuid": "181ecd5a-f242-11ec-82f1-0242ac150010",
      "dig": {
        "alg": "sha256",
        "val": "ca93946485519b3aadf82de2f1654523c98f8afdf90da28ea1d0067a59d1341a"
      },
      "draft": true
    },
    "doc": {
      "$schema": "https://gobl.org/draft-0/bill/invoice",
      "code": "",
      "currency": "EUR",
      "issue_date": "2022-03-29",
      "supplier": {
        "tax_id": {
          "country": "ES",
          "code": "B28774008"
        },
        "name": "Biz España S.L.",
        "addresses": [
          {
            "num": "42",
            "street": "Calle Pradillo",
            "locality": "Madrid",
            "region": "Madrid",
            "code": "28002",
            "country": "ES"
          }
        ],
        "emails": [
          {
            "addr": "billing@bizspain.es"
          }
        ]
      },
      "customer": {
        "tax_id": {
          "country": "ES",
          "code": "B33105842"
        },
        "name": "Customer Spain S.L.",
        "addresses": [
          {
            "num": "10",
            "street": "Calle Mayor",
            "locality": "Madrid",
            "region": "Madrid",
            "code": "28003",
            "country": "ES"
          }
        ],
        "emails": [
          {
            "addr": "sam@customer.com"
          }
        ]
      },
      "lines": [
        {
          "i": 1,
          "quantity": "50",
          "item": {
            "name": "Promotional mug",
            "price": "16.00"
          },
          "sum": "800.00",
          "taxes": [
            {
              "cat": "VAT",
              "rate": "standard",
              "percent": "21.0%"
            }
          ],
          "total": "800.00"
        }
      ],
      "totals": {
        "sum": "800.00",
        "total": "800.00",
        "taxes": {
          "categories": [
            {
              "code": "VAT",
              "rates": [
                {
                  "key": "standard",
                  "base": "800.00",
                  "percent": "21.0%",
                  "amount": "168.00"
                }
              ],
              "base": "800.00",
              "amount": "168.00"
            }
          ],
          "sum": "168.00"
        },
        "tax": "168.00",
        "total_with_tax": "968.00",
        "payable": "968.00"
      }
    },
    "sigs": []
  }
}

Let’s go over some of the important points in that response:

  • everything is wrapped inside a response containing the data and copies of key fields like the schemas, digest, and draft status,

  • we’ve created an entry in the silo. “Silo” is the fancy name we gave to the place where you store your GOBL Envelopes,

  • there is an id property that uniquely identifies this entry in the silo,

  • the data property includes a complete GOBL Envelope with the invoice,

  • the invoice has now been completed with all the totals and tax calculations, and,

  • the invoice’s code field is still empty.

We don’t recommend making HTTP POST calls like in this example as they do not include an ID that would make the request idempotent. This is fine for testing, but in production environments, you should pre-assign a UUID (v1) to the request and include it in the path in a PUT call. This way, if for some reason the request gets repeated, you’ll only have one copy.

Create a Job

Now for the exciting part. But first, let’s recap what we have:

  • A workflow with a set of steps to execute, with an ID.

  • A silo entry ID generated in the last request when we uploaded the Invoice.

Let’s put all these together and execute a job. Here’s the command to perform from the terminal and don’t forget to update the IDs with your values that were generated for the workflow and silo entry:

curl -H "Authorization: Bearer $INVOPOP_TOKEN" -X POST -F workflow_id=0d9602ab-a2e2-413c-adf0-7abf4dd25c12 -F silo_entry_id=181ecd5a-f242-11ec-82f1-0242ac150010 "https://api.invopop.com/transform/v1/jobs?wait=30" | jq .
{
  "id": "a42886a8-f23e-11ec-9be8-0242ac150010",
  "created_at": "2022-06-22T15:18:59.770Z",
  "updated_at": "2022-06-22T15:23:16.256Z",
  "silo_entry_id": "181ecd5a-f242-11ec-82f1-0242ac150010",
  "workflow_id": "0d9602ab-a2e2-413c-adf0-7abf4dd25c12",
  "status": "OK",
  "completed_at": "2022-06-22T15:23:16.256Z",
  "intents": [
    {
      "id": "a979ec1a-cd78-4ad0-bae6-d22df4b246ac",
      "created_at": "2022-06-22T15:18:59.821Z",
      "updated_at": "2022-06-22T15:19:00.064Z",
      "step_id": "4497eab3-5a47-4e34-9196-3d1cce237aff",
      "name": "Series Enumerator",
      "provider": "enumerator",
      "events": [
        {
          "index": 1,
          "status": "RUN",
          "at": "2022-06-22T15:18:59.832Z"
        },
        {
          "index": 2,
          "status": "OK",
          "at": "2022-06-22T15:19:00.064Z"
        }
      ],
      "completed": true
    },
    {
      "id": "483e20b0-4e9a-4fb3-bd76-9a1dabbc6c8f",
      "created_at": "2022-06-22T15:19:00.076Z",
      "updated_at": "2022-06-22T15:19:00.450Z",
      "step_id": "65018ad7-2cd9-4284-a5d5-974dd541f1f9",
      "name": "FacturaE",
      "provider": "facturae",
      "events": [
        {
          "index": 1,
          "status": "RUN",
          "at": "2022-06-22T15:19:00.094Z"
        },
        {
          "index": 2,
          "status": "OK",
          "at": "2022-06-22T15:19:00.450Z"
        }
      ],
      "completed": true
    },
    {
      "id": "655021e4-c941-4179-910b-5ba5e2ac439a",
      "created_at": "2022-06-22T15:19:00.456Z",
      "updated_at": "2022-06-22T15:19:01.054Z",
      "step_id": "2b16201f-6f38-4a0e-bd24-5e1e737b9305",
      "name": "PDF Generator",
      "provider": "pdf",
      "events": [
        {
          "index": 1,
          "status": "RUN",
          "at": "2022-06-22T15:19:00.464Z"
        },
        {
          "index": 2,
          "status": "OK",
          "at": "2022-06-22T15:19:01.053Z"
        }
      ],
      "completed": true
    },
    {
      "id": "f5c90cb2-03f1-494e-8a4c-98e6c535824a",
      "created_at": "2022-06-22T15:19:01.059Z",
      "updated_at": "2022-06-22T15:23:16.250Z",
      "step_id": "b3440891-067f-47c4-b6b8-6afc97d0be86",
      "name": "Send to Email",
      "provider": "email",
      "events": [
        {
          "index": 1,
          "status": "RUN",
          "at": "2022-06-22T15:19:01.068Z"
        },
        {
          "index": 2,
          "status": "OK",
          "at": "2022-06-22T15:19:01.083Z"
        }
      ],
      "completed": true
    }
  ],
  "envelope": {
    "$schema": "https://gobl.org/draft-0/envelope",
    "head": {
      "uuid": "181ecd5a-f242-11ec-82f1-0242ac150010",
      "dig": {
        "alg": "sha256",
        "val": "a9e2e745f095382db4814732d17ca936355a2e684371e5e9bcbbb6bfd24e61f4"
      }
    },
    "doc": {
      "$schema": "https://gobl.org/draft-0/bill/invoice",
      "code": "INV0200105",
      "currency": "EUR",
      "issue_date": "2022-03-29",
      "supplier": {
        "tax_id": {
          "country": "ES",
          "code": "B28774008"
        },
        "name": "Biz España S.L.",
        "addresses": [
          {
            "num": "42",
            "street": "Calle Pradillo",
            "locality": "Madrid",
            "region": "Madrid",
            "code": "28002",
            "country": "ES"
          }
        ],
        "emails": [
          {
            "addr": "billing@bizspain.es"
          }
        ]
      },
      "customer": {
        "tax_id": {
          "country": "ES",
          "code": "B33105842"
        },
        "name": "Customer Spain S.L.",
        "addresses": [
          {
            "num": "10",
            "street": "Calle Mayor",
            "locality": "Madrid",
            "region": "Madrid",
            "code": "28003",
            "country": "ES"
          }
        ],
        "emails": [
          {
            "addr": "sam@customer.com"
          }
        ]
      },
      "lines": [
        {
          "i": 1,
          "quantity": "50",
          "item": {
            "name": "Promotional mug",
            "price": "16.00"
          },
          "sum": "800.00",
          "taxes": [
            {
              "cat": "VAT",
              "rate": "standard",
              "percent": "21.0%"
            }
          ],
          "total": "800.00"
        }
      ],
      "totals": {
        "sum": "800.00",
        "total": "800.00",
        "taxes": {
          "categories": [
            {
              "code": "VAT",
              "rates": [
                {
                  "key": "standard",
                  "base": "800.00",
                  "percent": "21.0%",
                  "amount": "168.00"
                }
              ],
              "base": "800.00",
              "amount": "168.00"
            }
          ],
          "sum": "168.00"
        },
        "tax": "168.00",
        "total_with_tax": "968.00",
        "payable": "968.00"
      }
    },
    "sigs": [
      "eyJhbGciOiJFUzI1NiIsImtpZCI6Ijk1Nzg1MDY1LWJkN2YtNGY4MC1iYzc4LTQ3NTI2ZmZiODcxYiJ9.eyJ1dWlkIjoiZWMwNDkzODYtZjIyMC0xMWVjLWJlOGYtMDI0MmFjMTUwMDEwIiwiZGlnIjp7ImFsZyI6InNoYTI1NiIsInZhbCI6ImE5ZTJlNzQ1ZjA5NTM4MmRiNDgxNDczMmQxN2NhOTM2MzU1YTJlNjg0MzcxZTVlOWJjYmJiNmJmZDI0ZTYxZjQifX0.dexgs6CRQG-GgN-5X4hINOPoZFv0IhUH4XIsX08YztT2j-ndL9R3je7BjydNot9yVKd8BRsnDK-4Xe4JIr2KDA"
    ]
  },
  "attachments": [
    {
      "id": "483e20b0-4e9a-4fb3-bd76-9a1dabbc6c8f",
      "name": "facturae-invoice.xml",
      "hash": "70ffaede94d3466dbf23ddc8e0f69476de54106606f9f30938f9f44526600a8e",
      "mime": "text/xml; charset=utf-8",
      "size": 10941,
      "url": "https://silo.invopop.com/7ASThvIgEey-jwJCrBUAEA/SD4gsE6aT7O9dpodq7xsjw/facturae-invoice.xml?h=70ffaede94d3466d"
    },
    {
      "id": "655021e4-c941-4179-910b-5ba5e2ac439a",
      "name": "invoice.pdf",
      "hash": "fb9817cb640c2e0e26426fb3e34b868e64acafe1aab193a6c4ca109fbd43e230",
      "mime": "application/pdf",
      "size": 70898,
      "url": "https://silo.invopop.com/7ASThvIgEey-jwJCrBUAEA/ZVAh5MlBQXmRC1ul4qxDmg/invoice.pdf?h=fb9817cb640c2e0e"
    }
  ]
}

There is a lot of JSON data there, but let’s break it down into the key bits of data:

  • Everything is wrapped inside a “Job” object with the key fields like workflow_id and silo_entry_id.

  • Job status shows OK indicating that this job has been completed successfully.

  • The intents list describes all the steps the job has gone through for each of the connectors defined in the workflow.

  • envelope contains a copy of the invoice we uploaded earlier except it has now been assigned a code, and is no longer a draft.

  • attachments includes a list of links to all the files that have been generated for the envelope: an XML FacturaE document, and a single pdf.

Download the Results

Having completed a job, we can view the results in the Invopop Console or download the results directly based on the previous response. Take a look at the attachments attribute. Each attachment has a URL attribute that we can use to download the contents and then open the file:

curl "https://silo.invopop.com/7ASThvIgEey-jwJCrBUAEA/ZVAh5MlBQXmRC1ul4qxDmg/invoice.pdf?h=fb9817cb640c2e0e" > invoice.pdf
open invoice.pdf

You can also download the attachment directly in your browser by copying and pasting the URL.