Skip to main content
Correos Express · Odoo

Carriers in Odoo: Correos Express, the free OCA module and what each one covers

The OCA module delivery_correos_express is free, has branches from 14.0 to 19.0 and solves more than almost anyone admits. Here is the real diff against the paid connector, taken from both codebases.

Correos Express connector for Odoo

If you ship with Correos Express and run Odoo you have two options: install the OCA module delivery_correos_express, free and AGPL-3.0, or pay for a maintained connector. This article compares source code: the OCA module on branch 19.0 of the OCA/delivery-carrier repository and FlexigoTech's own connector, field by field and call by call.

In short: for your own shop with one contract, one fixed service and home delivery, the OCA module is enough. It stops being enough when you need scheduled pickups, pick-up point delivery, per-package weight, or a temporary API error not to leave the picking validated with no label.

What you need before you start

Three things, and no module gives you any of them. They are identical whichever route you take.

  • A contract with Correos Express. Both modules talk with your credentials and your rates; neither resells shipping.
  • Four values. User, password, customer code and sender code. In the OCA module they are the fields correos_express_username, correos_express_password, correos_express_customer_code and correos_express_sender_code. The sender code travels in solicitante when registering the shipment; the customer code in codRte and in keyCli when requesting the label.
  • Dependencies. The OCA module needs delivery_package_number and delivery_state from the same repository, plus the Python library unidecode. On Odoo.sh, unidecode goes in the repository requirements.txt or the install fails.

One routing detail: the OCA module picks the environment with the standard prod_environment flag on delivery.carrier and points to www.test.cexpr.es/wsps/ for testing and www.cexpr.es/wspsc/ for production. The prefix is not the same in both environments. Our connector uses /wspsc/ in both. Both prefixes answer on the test host, so if something fails there, start with the certificate and the credentials.

Feature by feature: what each one does

Every row comes from reading both modules, not from a brochure. Where the answer is "neither", that is written too.

FeatureOCA module delivery_correos_expressFlexigoTech connector
Licence and costAGPL-3.0, no licence costOPL-1, paid module
Odoo versionsBranches 14.0 to 19.0 of the repo17, 18 and 19
Dependenciesdelivery_package_number, delivery_state and unidecodedelivery, stock, sale, sale_stock (all core Odoo)
Label formatPDF and ZPL (API types 1 and 2)PDF (type 5, thermal) and ZPL; the dropdown also offers EPL, which travels with the same type as ZPL
Multi-packageSends numBultos from number_of_packages, but every package line goes with empty weight and dimensionsPer-package weight plus height, length and width when the package has them
Cash on deliveryNo: the reembolso field is sent emptyNeither: also sent empty
Scheduled pickupNot called at allCreate, modify, cancel, cut-off time and pickup tracking, plus creaRecogida when registering the shipment
Pick-up point (PUDO)No: codDirecDestino is always sent empty and there is no point lookupPoint lookup by radius and B-PACK service with a mandatory idPuntoExterno
Manifest / end of dayNot generatedNot as a document either; there are methods for shipment listing and report generation, but the daily close still happens in the carrier portal
Shipment cancellationPosts a chatter message saying there is no cancel methodCalls the stop-delivery service and, if the contract lacks it, records the cancellation as manual
Tracking coming backYes: writes state and history on the picking, driven by the daily delivery_state cronYes: own cron every 30 minutes with a configurable day window, 21 by default
Retry on API errorNo: any failure raises a UserError and stops thereCron every 5 minutes, backoff from 5 to 240 minutes and a maximum of 6 attempts per picking
Rate calculationThe API does not provide it: it returns the delivery product list price and says so in writingNeither: it returns the fixed price configured on the carrier and writes zero as the shipment exact price
Distinct API calls3: register shipment, label and tracking21 declared endpoints: registration, label and 19 further services, tracking included
Tests inside the module1854

Two rows tend to surprise people. The first is cash on delivery: neither of them sends it, so if you charge on delivery, today that is handled outside Odoo with both modules. The second is the rate: the Correos Express API does not quote shipments, so neither module computes anything. The OCA one returns the delivery product list price and leaves the warning in writing; our connector returns the carrier's fixed price. If you need the cart to compute shipping, that is solved with pricing rules in Odoo or with the OCA module delivery_price_method, not with the connector.

Where the OCA module is enough

Own shop, one contract, home delivery

You sell on your own site, everything ships on the same contracted product and you do not offer pick-up point delivery. You print on a Zebra with ZPL or on a laser printer with PDF. The OCA module covers that whole flow: shipment registration, tracking number on the picking, label attached in the chatter and status updated by the cron. A paid module will do nothing better here.

Odoo 14, 15 or 16

We maintain 17, 18 and 19 and will not pretend otherwise. The OCA repository has branches for 14.0, 15.0 and 16.0. If your Odoo is from those years, the OCA module is not the cheap option: it is the option.

Multi-package where every package is alike

If you are invoiced on the total shipment weight, the package list travelling with blank kilos changes nothing for you: the total weight does travel. The problem only appears when someone needs weight per package.

You have someone who touches code

The OCA module is short and readable: around 450 lines across carrier, requests and picking. If someone in-house reads Python, patching a field or porting the branch is an afternoon of work and the control is yours.

Where it falls short and what that costs in manual work

No opinion here: this is what the code does not do, and therefore what someone does by hand.

  • Pick-ups are requested outside. The OCA module calls no pick-up service: the daily notice to the carrier goes through the portal, the phone or an already agreed fixed route.
  • You cannot sell pick-up point delivery from Odoo. The destination point field is sent empty and there is no point lookup, so an order with pick-up point delivery leaves the picking flow.
  • Cancelling is a message, not an action. The module writes in the chatter that Correos Express offers no method to cancel a registered shipment. That is true for the registration call; the stop-delivery service exists separately and has to be enabled in your contract.
  • An API outage leaves the picking half done. Any exception surfaces as a user error and there is no retry. With a few shipments a day someone presses the button again; when there are hundreds, someone has to hunt them down one by one.
  • The reprint-label button only shows on a validated picking. It is conditioned on the state being done and on a tracking number existing. If your warehouse prints before validating, the button is not where they look for it.

The test certificate: the most repeated incident

Before switching modules over a connection error, check this. When calling the test environment www.test.cexpr.es, Python fails with CERTIFICATE_VERIFY_FAILED. It is not the module. That host does serve the full chain, but issued by Correos' own CA: the server certificate is signed by AC SUB 2 CORREOS and that signature goes up to AC RAIZ CORREOS, a self-signed root that is not in the public CA store. Python trusts only that store, so it stops there. Production, www.cexpr.es, validates against public CAs with nothing to change.

You can check it in ten seconds with openssl s_client -connect www.test.cexpr.es:443: the chain it returns ends in a self-signed Correos root. The quick way out is verify=False, and it is a bad idea: it weakens every HTTPS call on that instance. The right fix is a PEM bundle holding that root, passed as verify only on that carrier's calls, so production and every other integration keep verifying against the default store. The step by step is in the Correos Express SSL error in Odoo.

How to check it actually works

The test is not that the module installs. It is generating a real label against your contract and seeing the number written on the picking. Four things have to be there:

  • The shipment number in the picking's tracking field, not only inside the PDF.
  • The label stored as an attachment, with the number in the file name.
  • The public tracking link resolving with that same number.
  • The package codes, one per package you declared.
Odoo picking with the Correos Express label generated and the shipment number written on it
Picking CENT/OUT/00136 after registration: flow state "Label OK", shipment number 1823059046850141, package code and the label PDF attached. If your test does not end on a screen like this, it is not working: it is compiling.

Verdict

Start with the OCA module. It is free, it exists on your version's branch, and the scenario it covers is the one most shops shipping with Correos Express are in. Install it, produce a real label and work with it for a couple of weeks.

After that, write down what you still do outside Odoo. If that list includes requesting pickups, offering pick-up points, chasing pickings with no label or declaring per-package weight, that is where a paid module earns its place: not by having more buttons, but by emptying that list. If the list is empty, you are done and you do not need to buy anything.

Who sets it up is a separate conversation: installation, credentials and the certificate bundle cost the same with the free module as with the paid one. We cover that in OCA module rollout and in logistics in Odoo.

Where to go next

OCA Correos Express moduleThe free module, and what it takes to get it runningFlexigoTech Correos Express connectorThe paid module: pickups, PUDO, retries and cancellationFull OCA versus paid comparisonThe same decision, with the API errors you will meet in production

Frequently asked questions

Is there a free Correos Express module for Odoo?

Yes: delivery_correos_express, in the OCA/delivery-carrier repository under AGPL-3.0, with branches from 14.0 to 19.0. It covers shipment registration, PDF or ZPL labels and status updates.

Does the OCA module produce thermal printer labels?

Yes, in ZPL. The label type is a dropdown with two options, PDF and ZPL, which are types 1 and 2 of the Correos Express API. If your printer speaks another language, the module does not get there.

Can I offer pick-up point delivery with the OCA module?

Not from Odoo. The destination point field is always sent empty and the module includes no point lookup, so an order with pick-up point delivery is handled outside the picking.

Why does shipping show as 0 € on the order?

Because the Correos Express API does not quote shipments. The OCA module says so explicitly and returns the delivery product list price; our connector returns the carrier's fixed price and writes zero as the shipment exact price. Shipping cost is set with pricing rules in Odoo or with the OCA module delivery_price_method.

Can a registered shipment be cancelled?

Shipment registration has no cancellation: the OCA module writes that in the chatter and stops there. There is a separate stop-delivery service, which must be enabled in your contract, and our connector does call it.

What we do about this

Correos Express connectorWhat it does, screenshots, versions and price.

Want someone to look at your specific case?

Contract, Odoo version, volume and what you do outside the ERP today. That is enough to tell whether the OCA module is all you need, and we say so even when the answer is yes.

Talk to an engineer