Payment integrations
Connect Woovi, AbacatePay or Stripe and issue the NFS-e automatically for every confirmed payment.
Connect your payment platform account to Corvo. When a payment is confirmed, Corvo issues the NFS-e through the same path as the API: it checks the company and certificate, uses one plan credit and sends the invoice to the city.
How it works
- You create a connection (
POST /v1/integrations/connections) and get itswebhookUrl. - Register that address in the payment platform dashboard. The platform then notifies Corvo for every payment.
- Corvo checks the notice's authentication, stores the event and answers right away. Processing happens in the background.
- If the payment is confirmed and a service rule exists, the invoice is issued. The competence date is the confirmation date (São Paulo time zone).
- The same payment never produces two invoices, even if the platform sends the notice again.
Routes
| Method | Route | Description |
|---|---|---|
| GET | /v1/integrations/providers | Available platforms and the credential fields of each |
| POST | /v1/integrations/connections | Create a connection |
| GET | /v1/integrations/connections | List connections |
| GET | /v1/integrations/connections/:id | Get a connection |
| POST | /v1/integrations/connections/:id/validate | Check the credentials and identify the account |
| POST | /v1/integrations/connections/:id/activate | Start issuing automatically |
| POST | /v1/integrations/connections/:id/pause | Stop issuing; events are still stored |
| POST | /v1/integrations/connections/:id/disconnect | Disconnect for good |
| GET | /v1/integrations/connections/:id/rules | Get the service rules |
| PUT | /v1/integrations/connections/:id/rules | Replace the service rules |
| GET | /v1/integrations/connections/:id/events | Events received |
| GET | /v1/integrations/connections/:id/operations | Sales and the invoice status of each |
| PATCH | /v1/integrations/operations/:id/customer | Fill in the customer of a pending sale |
| POST | /v1/integrations/operations/:id/retry | Try to issue again |
| POST | /v1/integrations/inbound/:publicId | Address the payment platform calls (public, authenticated by the connector) |
Connect an account
1. Create the connection
curl -X POST "$BASE_URL/v1/integrations/connections" -H "X-API-Key: $CORVO_API_KEY" -H "Content-Type: application/json" -d '{
"provider": "woovi",
"companyId": "<company id>",
"environment": "test",
"credentials": {},
"activeFrom": "2026-11-01T00:00:00Z"
}'2. Set the service rule and activate
curl -X PUT "$BASE_URL/v1/integrations/connections/$CONNECTION_ID/rules" -H "X-API-Key: $CORVO_API_KEY" -H "Content-Type: application/json" -d '{ "rules": [ { "service": { "code": "010101", "description": "Consulting" }, "sendEmail": true } ] }'
curl -X POST "$BASE_URL/v1/integrations/connections/$CONNECTION_ID/validate" -H "X-API-Key: $CORVO_API_KEY"
curl -X POST "$BASE_URL/v1/integrations/connections/$CONNECTION_ID/activate" -H "X-API-Key: $CORVO_API_KEY"A rule without externalProductId applies to any product. To give a product a different service, send another rule with its externalProductId. Payments made before activeFrom are ignored. With allowAnonymousCustomer: true, the invoice is issued without a customer when the payment carries no CPF/CNPJ.
By platform
Woovi
- There is no credential to provide: send
"credentials": {}. Corvo generates thewebhookTokenand returns it insecrets.webhookTokenonly in the creation response. Thetestenvironment uses the Woovi sandbox andliveuses the production account. - In Woovi, create a webhook with the connection
webhookUrland the paid charge event (OPENPIX:CHARGE_COMPLETED). Under HTTP headers, add anAuthorizationheader with thewebhookTokenin the Value field. - The invoice customer is the charge customer, never whoever paid the Pix.
- Each charge becomes one invoice, identified by its
correlationID. The service description on the invoice is the chargecomment; without one, the company default is used. - Refunds: also select
PIX_TRANSACTION_REFUND_SENT_CONFIRMEDin the webhook. Corvo links the refund to the sale by the PixendToEndId. A partial refund is ignored.
AbacatePay
- Credential:
apiKey, an AbacatePay API v2 key (Integration > API > + New key) with theCUSTOMER:READandPRODUCT:READpermissions. Corvo generates thewebhookSecretand returns thewebhookUrlwith?webhookSecret=...only in the creation response. Keep that address. - In AbacatePay, create a webhook: paste the
webhookUrlin the URL field andsecrets.webhookSecret(returned only on creation) in the Secret field, and selectcheckout.completedandtransparent.completed. Corvo accepts the Standard Webhooks signature (webhook-id,webhook-timestamp,webhook-signature) and the legacy format (?webhookSecret=). - The event
devModemust match the connection environment: test events issue no invoice on aliveconnection, and the other way around. - The webhook carries the CPF/CNPJ masked, so Corvo looks the customer up on AbacatePay with your key and uses the full document. If the customer has no document, the sale stays pending (
customer_tax_id_missing), or is issued without a customer if the rule hasallowAnonymousCustomer. - A rule's
externalProductIdis the checkout itemid. The service description on the invoice is the product name (Corvo looks it up with your key); without thePRODUCT:READpermission, the company default is used. - Refunds: also select
checkout.refundedandtransparent.refundedin the webhook. Without automatic cancellation, a refund or dispute after the invoice opens therefund_after_invoicependency and the invoice is not cancelled.
Sales that need attention
When a sale cannot become an invoice by itself, it shows up in GET /v1/integrations/connections/:id/operations with fiscalStatus and blockReason.
| blockReason | What to do |
|---|---|
customer_tax_id_missing | The platform did not send a full CPF/CNPJ. Provide it with PATCH /v1/integrations/operations/:id/customer, then call POST /v1/integrations/operations/:id/retry. |
no_rule / ambiguous_rule | Create or adjust the rules, then call retry. |
invoice_rejected | Fiscal validation refused the request. The message names the field; fix it and call retry. |
quota_exceeded | No credits or plan limit reached. After fixing it, call retry. |
connection_inactive | The connection is paused or needs to be authorized again. Reactivate it and call retry. |
company_not_ready | The company is not ready or the certificate is missing, expired or invalid. Fix the registration and call retry. |
before_active_from | The payment happened before the connection start date. No invoice is issued. |
refunded / disputed | The payment was refunded or disputed before the invoice. No invoice is issued. |
refund_after_invoice | A refund or dispute arrived after the invoice and automatic cancellation is off. The invoice stays authorized. To cancel it, use POST /v1/invoices/:id/cancel; for future refunds, turn on cancelOnRefund on the rule (a dispute never cancels). |
cancel_requested | Nothing to do: Corvo asked for the invoice to be cancelled (reason "Cancelado por reembolso"). Follow the result on the invoice page. |
cancel_failed | The cancellation could not be requested (for example, the invoice is in a state that does not allow it). Check the invoice and, if it can be cancelled, use retry. |