Get a signature
PlannedDesigned and scheduled for the v1 API. The contract can still change; the route is not served yet.
Returns the signature request. Once the worker signs, signed_document carries a signed link to the signed PDF, valid for 15 minutes, and certificate the e.firma they used. Get the signature again for a new link.
Needs the signatures:read scope.
oauth2 signatures:readAuthorizationBearer <token>OAuth 2.0 client credentials. Exchange your client_id and client_secret at /oauth/token of the environment for a bearer token valid for one hour. The playground of every operation asks for your own client and keeps it in your browser tab only.
Scope: signatures:read
id*stringThe signature id.
^sig_[0-7][0-9a-hjkmnp-tv-z]{25}$OK
application/json- response
id*string^sig_[0-7][0-9a-hjkmnp-tv-z]{25}$external_id*stringYour id, as you sent it.
status*stringawaiting_worker until the worker signs; signed once they did; rejected if they declined; expired when the signing link ran out unused.
"awaiting_worker""signed""rejected""expired"worker_id*string^wrk_[0-7][0-9a-hjkmnp-tv-z]{25}$purpose?string|nullsigning*Where the worker reviews and signs the document with their e.firma.
signed_document?|Signed link to download the signed PDF, valid for 15 minutes. heru creates a new one every time you get the signature. Null until status is signed.
certificate?|nullcreated_at*stringdate-timeupdated_at*stringdate-timecurl -X GET 'https://api.dev.b2b.heru.app/v1/signatures/sig_01m4rcp7xvfrct34z0q3s0r2yb'{ "id": "sig_01m4rcp7xvfrct34z0q3s0r2yb", "external_id": "CTR-2026-000417", "status": "signed", "worker_id": "wrk_01m4ra8w0he5esnnsew0v9ffkv", "purpose": "Contrato de prestación de servicios", "signing": { "url": null, "expires_at": null }, "signed_document": { "url": "https://download.heru.app/signatures/sig_01m4rcp7xvfrct34z0q3s0r2yb/contrato-prestacion-servicios-DRV-000088213.pdf?Expires=1791993789&KeyName=b2b-files&Signature=Qz8vT3pLm2Kx7wN4cB9rY6dA1f", "expires_at": "2026-10-12T16:18:09.000Z", "content_type": "application/pdf", "filename": "contrato-prestacion-servicios-DRV-000088213.pdf" }, "certificate": { "serial_number": "00001000000504465028", "rfc": "HEGL900101K44", "signed_at": "2026-10-12T16:03:09.584Z" }, "created_at": "2026-10-12T15:46:20.731Z", "updated_at": "2026-10-12T16:03:09.584Z"}Sign a document with the worker's e.firmaPOST
For digital contracts. You send the PDF; the worker reviews and signs it with their e.firma on a hosted page. You get the signed document and the certificate data. Needs the `signatures:write` scope.
Issue an invoicePOST
Issues a CFDI 4.0. **Who issues it** - Your company: send nothing, or `issuer.company_id` to pick one of your companies. - A merchant: `issuer.merchant_id`. - A worker with their own CSD: `issuer.worker_id`. - heru, on a worker's behalf (the worker needs no CSD): `third_party.worker_id`. - Your company, on another taxpayer's behalf: `third_party` with their RFC. **Who receives it** - One of your companies, a worker or a merchant: `receiver.company_id`, `receiver.worker_id` or `receiver.merchant_id`. heru fills their SAT data. - Anyone else: `receiver` with their RFC, name, regime and postal code. **Which companies can issue.** It depends on the credential: see [Companies](/companies). **Files.** Get the XML or the PDF with `GET /invoices/{id}/download`, which needs the `invoices:download` scope. **Synchronous.** heru stamps the CFDI with the PAC before answering, usually in 2 to 5 seconds, and returns it with its folio fiscal. Wait up to 30 seconds. If the PAC or the SAT do not answer in time you get `503` and nothing is created: retry after `Retry-After` with the same `Idempotency-Key`. If the connection drops or you get another `5xx`, retry the same way: you get the CFDI that was already stamped, never a second one. Needs the `invoices:write` scope.