Description
n8n-nodes-salvy
This is an n8n community node for the Salvy public API (v3). It lets you manage phone accounts, employees, cost centers, assets, asset statements and invoices from your n8n workflows, and start workflows from Salvy events with the Salvy Trigger.
📖 Salvy API documentation: docs.salvy.com.br · API keys and scopes · Webhooks
n8n is a fair-code licensed workflow automation platform.
- Installation
- Credentials
- Operations
- Trigger
- Compatibility
- Development
- Resources
- Get Many operations return one item per record, with Return All / Limit handling the API’s page-based pagination. With Return All, every page request carries the same filters and sort options as the first.
- With Limit, each record also gets a
totalCountfield: the number of records matching the filters across all pages (the API’spagination.totalCount). To count records, run Get Many with Limit 1 and readtotalCountfrom the single item, instead of fetching everything with Return All. If nothing matches, you get a single item withtotalCount: 0. Return All items have nototalCount; the number of items is the total. - Fields with a fixed set of values are dropdowns (multi-selects where the API takes several values), and their descriptions list the raw API values for use in expressions. When an AI agent fills a multi-select through Let the model define this parameter, n8n passes it as text with only the description you write, so the node accepts a comma-separated list; copy the listed values into that description so the model uses them.
- Download operations return the file as binary data (field
databy default). - Simulate SMS and Simulate Signature are sandbox-only in the API; use them with a sandbox key.
- Batch operations (Batch Sync, Batch Update Cost Center) run in the background and return a task ID; poll it with Task > Get and Task > Get Results.
- The experimental WebRTC token endpoint is intentionally not included.
- Pick one or more Events; the list is loaded from
GET /api/v3/webhook-event-types, so new event types show up without a node update. - When the workflow is activated, the node registers its production webhook URL with
POST /api/v3/webhook-endpointsand stores the endpoint ID and signing secret in the workflow’s static data. Deactivating the workflow deletes the endpoint. If the stored endpoint was registered for a different URL or event list, it is replaced. - Every delivery is verified with the Standard Webhooks (Svix) signature scheme: HMAC-SHA256 over the raw body, constant-time comparison, any of several
v1signatures accepted, and timestamps more than 5 minutes off rejected. Invalid deliveries get401and do not start the workflow. - Each delivery produces one item:
{ type, timestamp, data }. - A company API key with the
webhook-endpoint:create,webhook-endpoint:readandwebhook-endpoint:deletescopes. - Your n8n instance must be reachable from the internet over HTTPS (the API only accepts
https://webhook URLs). SetWEBHOOK_URLif n8n runs behind a proxy.
Installation
Follow the installation guide in the n8n community nodes documentation and install the package @salvyltd/n8n-nodes-salvy.
Credentials
The node uses a Salvy API credential with a single field, API Key.
1. In the Salvy dashboard, create a company or organization API key (API keys guide).
2. In n8n, create a new Salvy API credential and paste the key.
The key is sent as Authorization: Bearer to https://api.salvy.com.br. Sandbox and production keys use the same base URL; the key decides the environment (environments). n8n tests the credential with a read-only call to GET /api/v3/companies.
Operations
| Resource | Operations |
| ——————- | ——————————————————————————————————————————————————————————————————————— |
| Area Code | Get Many |
| Asset | Archive, Create, Create Timeline Note, Delete, Get, Get Many, Unarchive, Update |
| Asset Statement | Download Signed File, Get, Get Many, Send, Simulate Signature |
| Company | Get Many |
| Cost Center | Create, Delete, Get, Get Many, Update |
| Employee | Batch Sync, Create, Delete, Get, Get Many, Update |
| Invoice | Download NFe PDF, Download NFe XML, Download PDF, Get, Get Many, Get Phone Accounts |
| Phone Account | Activate, Batch Update Cost Center, Block, Cancel, Create Mobile, Create Mobile DID, Get, Get Data Balance, Get eSIM, Get Many, Get SMS Messages, Simulate SMS, Top Up Data, Unblock, Unschedule Cancellation, Update |
| Phone Account Group | Create, Delete, Get, Get Many, Update |
| Plan | Get, Get Many |
| Task | Get, Get Results |
Notes:
The total rides on each record rather than in a separate summary item so the output stays one item per record, as in every other mode, and downstream nodes and AI agents read it from the first item.
Operation coverage
Generated from openapi/salvy-v3.json by npm run generate. “generated” means the @devlikeapro/n8n-openapi-node output was used as is; “fixed” lists what had to be corrected or added on top of it.
| Resource | Operation | Endpoint | Status | Notes |
| ——————- | ———————— | ———————————————————- | ——— | ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— |
| Area Code | Get Many | GET /api/v3/area-codes | fixed | enum fields list their API values in the description; not paginated (no pagination in the response): no Return All/Limit; optional query params grouped under Filters/Options (generator sends every param, even empty); list response split into one item per record (data) |
| Asset Statement | Download Signed File | GET /api/v3/asset-statements/{id}/signed-file | fixed | file response returned as n8n binary data (generator: JSON only) |
| Asset Statement | Get Many | GET /api/v3/asset-statements | fixed | array query params as comma-separated text (generator sends them as a JSON string); array query params as multi-select (generator sends them as a JSON string); enum fields list their API values in the description; page/pageSize replaced by Return All + Limit (page sent once, in the query); Return All re-sends every query param on each page (generic pagination replaces qs); optional query params grouped under Filters/Options (generator sends every param, even empty); list response split into one item per record (data); Limit mode adds pagination.totalCount to each record as totalCount |
| Asset Statement | Get | GET /api/v3/asset-statements/{id} | generated | — |
| Asset Statement | Send | POST /api/v3/asset-statements | fixed | oneOf body merged; branch-only fields shown per type; enum fields list their API values in the description; assetIds (array of IDs) as comma-separated text (generator: raw JSON field) |
| Asset Statement | Simulate Signature | POST /api/v3/asset-statements/{id}/simulate-signature | generated | — |
| Asset | Archive | POST /api/v3/assets/{id}/archive | generated | — |
| Asset | Create Timeline Note | POST /api/v3/assets/{id}/timeline-notes | fixed | optional body fields grouped under Additional Fields (generator sends every field, even empty) |
| Asset | Create | POST /api/v3/assets | fixed | nullable types (OpenAPI 3.1) collapsed; enum fields list their API values in the description; nested customFields exposed as a JSON field (generator: first level only); optional body fields grouped under Additional Fields (generator sends every field, even empty) |
| Asset | Delete | DELETE /api/v3/assets/{id} | fixed | 204 No Content mapped to { success: true } |
| Asset | Get Many | GET /api/v3/assets | fixed | includeArchived is a string in the spec; exposed as a boolean; array query params as multi-select (generator sends them as a JSON string); enum fields list their API values in the description; array query params as comma-separated text (generator sends them as a JSON string); page/pageSize replaced by Return All + Limit (page sent once, in the query); Return All re-sends every query param on each page (generic pagination replaces qs); optional query params grouped under Filters/Options (generator sends every param, even empty); list response split into one item per record (data); Limit mode adds pagination.totalCount to each record as totalCount |
| Asset | Get | GET /api/v3/assets/{id} | generated | — |
| Asset | Unarchive | POST /api/v3/assets/{id}/unarchive | fixed | enum fields list their API values in the description |
| Asset | Update | PATCH /api/v3/assets/{id} | fixed | nullable types (OpenAPI 3.1) collapsed; enum fields list their API values in the description; nested customFields exposed as a JSON field (generator: first level only); optional body fields grouped under Update Fields (generator sends every field, even empty) |
| Company | Get Many | GET /api/v3/companies | fixed | page/pageSize replaced by Return All + Limit (page sent once, in the query); Return All re-sends every query param on each page (generic pagination replaces qs); list response split into one item per record (data); Limit mode adds pagination.totalCount to each record as totalCount |
| Cost Center | Create | POST /api/v3/cost-centers | fixed | nullable types (OpenAPI 3.1) collapsed; enum fields list their API values in the description; optional body fields grouped under Additional Fields (generator sends every field, even empty) |
| Cost Center | Delete | DELETE /api/v3/cost-centers/{id} | fixed | nullable types (OpenAPI 3.1) collapsed; 204 No Content mapped to { success: true } |
| Cost Center | Get Many | GET /api/v3/cost-centers | fixed | array query params as multi-select (generator sends them as a JSON string); enum fields list their API values in the description; page/pageSize replaced by Return All + Limit (page sent once, in the query); Return All re-sends every query param on each page (generic pagination replaces qs); optional query params grouped under Filters/Options (generator sends every param, even empty); list response split into one item per record (data); Limit mode adds pagination.totalCount to each record as totalCount |
| Cost Center | Get | GET /api/v3/cost-centers/{id} | generated | — |
| Cost Center | Update | PATCH /api/v3/cost-centers/{id} | fixed | nullable types (OpenAPI 3.1) collapsed; enum fields list their API values in the description; optional body fields grouped under Update Fields (generator sends every field, even empty) |
| Employee | Batch Sync | POST /api/v3/employees/batch-sync | fixed | nested employees exposed as a JSON field (generator: first level only) |
| Employee | Create | POST /api/v3/employees | fixed | enum fields list their API values in the description; nested address hand-written as a collection (generator: first level only); optional body fields grouped under Additional Fields (generator sends every field, even empty) |
| Employee | Delete | DELETE /api/v3/employees/{id} | fixed | 204 No Content mapped to { success: true } |
| Employee | Get Many | GET /api/v3/employees | fixed | array query params as multi-select (generator sends them as a JSON string); enum fields list their API values in the description; page/pageSize replaced by Return All + Limit (page sent once, in the query); Return All re-sends every query param on each page (generic pagination replaces qs); optional query params grouped under Filters/Options (generator sends every param, even empty); list response split into one item per record (data); Limit mode adds pagination.totalCount to each record as totalCount |
| Employee | Get | GET /api/v3/employees/{id} | generated | — |
| Employee | Update | PATCH /api/v3/employees/{id} | fixed | nullable types (OpenAPI 3.1) collapsed; enum fields list their API values in the description; nested address hand-written as a collection (generator: first level only); optional body fields grouped under Update Fields (generator sends every field, even empty) |
| Invoice | Download NFe PDF | GET /api/v3/invoices/{id}/nfe/pdf | fixed | file response returned as n8n binary data (generator: JSON only) |
| Invoice | Download NFe XML | GET /api/v3/invoices/{id}/nfe/xml | fixed | file response returned as n8n binary data (generator: JSON only) |
| Invoice | Download PDF | GET /api/v3/invoices/{id}/pdf | fixed | file response returned as n8n binary data (generator: JSON only) |
| Invoice | Get Many | GET /api/v3/invoices | fixed | array query params as multi-select (generator sends them as a JSON string); enum fields list their API values in the description; page/pageSize replaced by Return All + Limit (page sent once, in the query); Return All re-sends every query param on each page (generic pagination replaces qs); optional query params grouped under Filters/Options (generator sends every param, even empty); list response split into one item per record (data); Limit mode adds pagination.totalCount to each record as totalCount |
| Invoice | Get Phone Accounts | GET /api/v3/invoices/{id}/phone-accounts | fixed | page/pageSize replaced by Return All + Limit (page sent once, in the query); Return All re-sends every query param on each page (generic pagination replaces qs); list response split into one item per record (data); Limit mode adds pagination.totalCount to each record as totalCount |
| Invoice | Get | GET /api/v3/invoices/{id} | generated | — |
| Phone Account Group | Create | POST /api/v3/phone-account-groups | fixed | enum fields list their API values in the description; optional body fields grouped under Additional Fields (generator sends every field, even empty) |
| Phone Account Group | Delete | DELETE /api/v3/phone-account-groups/{id} | fixed | 204 No Content mapped to { success: true } |
| Phone Account Group | Get Many | GET /api/v3/phone-account-groups | fixed | page/pageSize replaced by Return All + Limit (page sent once, in the query); Return All re-sends every query param on each page (generic pagination replaces qs); list response split into one item per record (data); Limit mode adds pagination.totalCount to each record as totalCount |
| Phone Account Group | Get | GET /api/v3/phone-account-groups/{id} | generated | — |
| Phone Account Group | Update | PATCH /api/v3/phone-account-groups/{id} | fixed | enum fields list their API values in the description; optional body fields grouped under Update Fields (generator sends every field, even empty) |
| Phone Account | Activate | POST /api/v3/phone-accounts/{id}/activate | fixed | optional body fields grouped under Additional Fields (generator sends every field, even empty) |
| Phone Account | Batch Update Cost Center | POST /api/v3/phone-accounts/batch-update-cost-center | fixed | nullable types (OpenAPI 3.1) collapsed; phoneAccountIds (array of IDs) as comma-separated text (generator: raw JSON field) |
| Phone Account | Block | POST /api/v3/phone-accounts/{id}/block | fixed | enum fields list their API values in the description; optional body fields grouped under Additional Fields (generator sends every field, even empty) |
| Phone Account | Cancel | POST /api/v3/phone-accounts/{id}/cancel | fixed | enum fields list their API values in the description; optional body fields grouped under Additional Fields (generator sends every field, even empty) |
| Phone Account | Create Mobile DID | POST /api/v3/phone-accounts/mobile-did | fixed | nullable types (OpenAPI 3.1) collapsed; nested customFields exposed as a JSON field (generator: first level only); optional body fields grouped under Additional Fields (generator sends every field, even empty) |
| Phone Account | Create Mobile | POST /api/v3/phone-accounts/mobile | fixed | oneOf body merged; branch-only fields shown per simType; nullable types (OpenAPI 3.1) collapsed; enum fields list their API values in the description; nested customFields exposed as a JSON field (generator: first level only); optional body fields grouped under Additional Fields (generator sends every field, even empty) |
| Phone Account | Get Data Balance | GET /api/v3/phone-accounts/{id}/balance | generated | — |
| Phone Account | Get Many | GET /api/v3/phone-accounts | fixed | array query params as multi-select (generator sends them as a JSON string); enum fields list their API values in the description; array query params as comma-separated text (generator sends them as a JSON string); page/pageSize replaced by Return All + Limit (page sent once, in the query); Return All re-sends every query param on each page (generic pagination replaces qs); optional query params grouped under Filters/Options (generator sends every param, even empty); list response split into one item per record (data); Limit mode adds pagination.totalCount to each record as totalCount |
| Phone Account | Get SMS Messages | GET /api/v3/phone-accounts/{id}/sms-messages | fixed | array query params as multi-select (generator sends them as a JSON string); enum fields list their API values in the description; page/pageSize replaced by Return All + Limit (page sent once, in the query); Return All re-sends every query param on each page (generic pagination replaces qs); optional query params grouped under Filters/Options (generator sends every param, even empty); list response split into one item per record (data); Limit mode adds pagination.totalCount to each record as totalCount |
| Phone Account | Get eSIM | GET /api/v3/phone-accounts/{id}/esim | generated | — |
| Phone Account | Get | GET /api/v3/phone-accounts/{id} | generated | — |
| Phone Account | Simulate SMS | POST /api/v3/phone-accounts/{id}/sms | fixed | 204 No Content mapped to { success: true } |
| Phone Account | Top Up Data | POST /api/v3/phone-accounts/{id}/top-up-data | generated | — |
| Phone Account | Unblock | POST /api/v3/phone-accounts/{id}/unblock | generated | — |
| Phone Account | Unschedule Cancellation | POST /api/v3/phone-accounts/{id}/unschedule-cancellation | generated | — |
| Phone Account | Update | PATCH /api/v3/phone-accounts/{id} | fixed | nullable types (OpenAPI 3.1) collapsed; nested customFields exposed as a JSON field (generator: first level only); optional body fields grouped under Update Fields (generator sends every field, even empty) |
| Plan | Get Many | GET /api/v3/plans | fixed | not paginated (no pagination in the response): no Return All/Limit; list response split into one item per record (data) |
| Plan | Get | GET /api/v3/plans/{id} | generated | — |
| Task | Get Results | GET /api/v3/tasks/{id}/results | fixed | array query params as multi-select (generator sends them as a JSON string); enum fields list their API values in the description; page/pageSize replaced by Return All + Limit (page sent once, in the query); Return All re-sends every query param on each page (generic pagination replaces qs); optional query params grouped under Filters/Options (generator sends every param, even empty); response is a oneOf union keyed by type; items are passed through as-is (the generator does not read responses); list response split into one item per record (data); Limit mode adds pagination.totalCount to each record as totalCount |
| Task | Get | GET /api/v3/tasks/{id} | generated | — |
| — | — | POST /api/v3/webrtc/tokens | excluded | WebRTC is experimental; excluded from this node on purpose. |
Trigger
Salvy Trigger starts a workflow when Salvy sends a webhook event.
Requirements:
Compatibility
Built with @n8n/node-cli 0.52.2. Tested by loading the built node into n8n 2.43.4.
Development
npm install
npm run spec:refresh # download the latest OpenAPI spec from docs.salvy.com.br
npm run generate # regenerate nodes/Salvy/Salvy.properties.generated.ts
npm run lint
npm run build
npm test # build, then run the trigger's signature and webhook lifecycle tests
npm run dev # run n8n locally with the node loaded
The node is declarative: nodes/Salvy/Salvy.properties.generated.ts holds every parameter and request mapping and is produced at build time from the vendored spec. The generator is a dev dependency only; the published package has no runtime dependencies. Operation names and English descriptions live in scripts/salvy-operations.mjs and scripts/i18n/descriptions.en.json; npm run generate fails if the spec gains an unmapped operation or an untranslated description.


