# List business entities for a customer Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-business-entities-GET GET /partner/commenda-os/customers/{customerId}/business-entities List the business entities for one of your customers. List the business entities for one of your customers. # Create a business entity Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-business-entities-POST POST /partner/commenda-os/customers/{customerId}/business-entities Create a reusable Commenda OS business entity for one of your customers. Use the returned `businessEntity.id` as a `BUSINESS_ENTITY` resource id when registering corporate incorporation participants. Create a reusable Commenda OS business entity for one of your customers. For incorporation flows, use the returned `businessEntity.id` as `resource.resourceId` when registering a corporate participant with `resource.resourceType: "BUSINESS_ENTITY"`. # Get a business entity Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-business-entities-id-GET GET /partner/commenda-os/customers/{customerId}/business-entities/{businessEntityId} Retrieve a single business entity for one of your customers. Retrieve a single business entity for one of your customers. # Update a business entity Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-business-entities-id-PATCH PATCH /partner/commenda-os/customers/{customerId}/business-entities/{businessEntityId} Partially update a reusable Commenda OS business entity. Omitted fields are left unchanged. Use this endpoint to complete corporate shareholder details before registering or validating incorporation participants. Partially update a reusable Commenda OS business entity. Use this endpoint to complete corporate shareholder details before registering the business entity as an incorporation participant, or before re-running incorporation validation after Commenda requests corrections. # List documents for a business entity Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-business-entities-id-documents-GET GET /partner/commenda-os/customers/{customerId}/business-entities/{businessEntityId}/documents List documents for a customer's business entity. List documents for a customer's business entity. # List supported document types Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-business-entities-id-documents-supported-GET GET /partner/commenda-os/customers/{customerId}/business-entities/{businessEntityId}/documents/supported List the document types Commenda OS supports for a customer's business entity. List the document types Commenda OS supports for a customer's business entity. # List government identifiers Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-business-entities-id-government-identifiers-GET GET /partner/commenda-os/customers/{customerId}/business-entities/{businessEntityId}/government-identifiers List government identifiers attached to a customer's business entity. List government identifiers attached to a customer's business entity. # Get a government identifier Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-business-entities-id-government-identifiers-government-identifier-id-GET GET /partner/commenda-os/customers/{customerId}/business-entities/{businessEntityId}/government-identifiers/{governmentIdentifierId} Retrieve a single government identifier for a customer's business entity. Retrieve a single government identifier for a customer's business entity. # List locations for a business entity Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-business-entities-id-locations-GET GET /partner/commenda-os/customers/{customerId}/business-entities/{businessEntityId}/locations List locations attached to a customer's business entity. List locations attached to a customer's business entity. # Create a location Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-business-entities-id-locations-POST POST /partner/commenda-os/customers/{customerId}/business-entities/{businessEntityId}/locations Create a reusable Commenda OS location for a customer's business entity. Create a reusable Commenda OS location for a customer's business entity. Use this endpoint when an incorporation requires a partner-provided registered office address and the customer does not already have the location in Commenda OS. # Get a location Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-business-entities-id-locations-location-id-GET GET /partner/commenda-os/customers/{customerId}/business-entities/{businessEntityId}/locations/{locationId} Retrieve a single location for a customer's business entity. Retrieve a single location for a customer's business entity. # Update a location Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-business-entities-id-locations-location-id-PATCH PATCH /partner/commenda-os/customers/{customerId}/business-entities/{businessEntityId}/locations/{locationId} Update a reusable Commenda OS location for a customer's business entity. Update a reusable Commenda OS location for a customer's business entity. Use this endpoint when an incorporation references an existing location that is missing required registered office address details. # List persons for a business entity Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-business-entities-id-persons-GET GET /partner/commenda-os/customers/{customerId}/business-entities/{businessEntityId}/persons List people associated with a customer's business entity. List people associated with a customer's business entity. Person responses include `residentialAddress` as a top-level field. They do not include a person `locations` array; Location resources are business-entity addresses. # List registrations for a business entity Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-business-entities-id-registrations-GET GET /partner/commenda-os/customers/{customerId}/business-entities/{businessEntityId}/registrations List registrations for a customer's business entity. List registrations for a customer's business entity. # Get a registration Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-business-entities-id-registrations-registration-id-GET GET /partner/commenda-os/customers/{customerId}/business-entities/{businessEntityId}/registrations/{registrationId} Retrieve a single registration for a customer's business entity. Retrieve a single registration for a customer's business entity. # List supported registrations for a business entity Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-business-entities-id-registrations-supported-GET GET /partner/commenda-os/customers/{customerId}/business-entities/{businessEntityId}/registrations/supported List the registrations Commenda OS supports for a customer's business entity. Returns the registration types available for a customer's business entity. The `businessEntityId` must match the provided `customerId`, or the API returns `404 Not Found`. # Upload a file Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-files-POST POST /partner/commenda-os/customers/{customerId}/files Upload a file with multipart/form-data and receive a reusable fileId. Stores bytes only; does not link the file to any other resource. Use the returned fileId with a separate attach call to put the file to work. Upload a file with `multipart/form-data` and receive a reusable `fileId`. This endpoint stores bytes only — it does not link the file to a person, a business entity, or a participant document. Use the returned `fileId` with a separate attach call to put the file to work. This is the only Commenda Partner API endpoint that accepts binary content. Files are scoped to the customer named in the path and can be referenced by any downstream attach call that takes a `fileId` for that customer. ## When to use this endpoint Call this before [upserting a participant document](/engine/incorporation/partner-incorporation-participant-documents-PUT) for an incorporation, or before any future endpoint that accepts a `fileId`. A single `fileId` can be reused across multiple attach calls without re-uploading bytes. ## Request Send a single multipart part named `file` containing the binary body. The part's filename and detected MIME type are stored as `fileName` and `mimeType` on the file record. No other fields are accepted. ## Limits | Limit | Value | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Maximum file size | 100 MB per request | | Request timeout | 120 seconds | | Accepted MIME types | `application/pdf`, `image/png`, `image/jpeg`, `image/heic`, `image/heif`, `image/tiff`, `image/webp`, `application/msword`, `application/vnd.openxmlformats-officedocument.wordprocessingml.document` | Requests that exceed the file-size limit return `413 Payload Too Large`. Requests with an unsupported MIME type return `415 Unsupported Media Type`. Commenda detects the MIME type from the uploaded part's content rather than trusting the declared `Content-Type` alone, so renaming a file extension does not change which limits apply. If you need to upload files larger than 100 MB, contact Commenda. A separate direct-to-object-storage upload flow is available for those cases. ## Example ```bash theme={null} curl --request POST \ --url 'https://api.prod.commenda.io/api/v1/partner/commenda-os/customers/77/files' \ --header 'x-api-key: ' \ --form 'file=@./passport.pdf;type=application/pdf' ``` ```json theme={null} { "file": { "fileId": 456, "fileName": "passport.pdf", "mimeType": "application/pdf", "fileSize": 382144, "customerId": 77 } } ``` # Commenda OS Partner API Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-introduction Commenda's core data model for business entities, people, files, and registrations. Base URL: ```text theme={null} https://api.prod.commenda.io/api/v1/partner/commenda-os ``` ## Authentication Pass your partner API key in the `x-api-key` header on every request. ```bash theme={null} curl --request GET \ --url 'https://api.prod.commenda.io/api/v1/partner/commenda-os/customers/77/business-entities' \ --header 'x-api-key: ' ``` ## Response conventions * List endpoints return `{ , count }`. * Detail endpoints return `{ }`. * All customer-scoped Commenda OS partner endpoints are scoped by `customerId`. * Requests without a valid `x-api-key` return `401` with `Missing x-api-key header` or `Invalid API key`. * Customer-scoped endpoints return `403` when the partner cannot access the requested customer. * Business-entity-scoped collection endpoints return `404 Business entity not found` when the `businessEntityId` does not belong to the specified customer. * Child detail endpoints return resource-specific `404` messages such as `Location not found`, `Government identifier not found`, or `Registration not found`. ## Available resources * [Business entities](/engine/commendaos/partner-api/commenda-os-business-entities-GET) * [Create business entities](/engine/commendaos/partner-api/commenda-os-business-entities-POST) * [Update business entities](/engine/commendaos/partner-api/commenda-os-business-entities-id-PATCH) * [Locations](/engine/commendaos/partner-api/commenda-os-business-entities-id-locations-GET) * [Persons](/engine/commendaos/partner-api/commenda-os-persons-GET) * [Government identifiers](/engine/commendaos/partner-api/commenda-os-business-entities-id-government-identifiers-GET) * [Upload files](/engine/commendaos/partner-api/commenda-os-files-POST) * [List business entity documents](/engine/commendaos/partner-api/commenda-os-business-entities-id-documents-GET) * [Registrations](/engine/commendaos/partner-api/commenda-os-business-entities-id-registrations-GET) # List persons for a customer Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-persons-GET GET /partner/commenda-os/customers/{customerId}/persons List people for one of your customers across their business entities. List people for one of your customers across their business entities. If the person you need does not exist yet, create them with [Create a person](/engine/commendaos/partner-api/commenda-os-persons-POST). Person responses include `residentialAddress` as a top-level field. They do not include a person `locations` array; Location resources are business-entity addresses. # Create a person Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-persons-POST POST /partner/commenda-os/customers/{customerId}/persons Create a reusable Commenda OS person for one of your customers. Use the returned `person.id` as a `KEY_PERSON` resource id when registering incorporation participants. For Singapore residential address requirements, include `residentialAddress`. Create a reusable Commenda OS person for one of your customers. Use this endpoint when an incorporation participant does not already exist in Commenda OS. After creation, pass the returned `person.id` as the participant resource id: ```json theme={null} { "participantType": "INDIVIDUAL", "resource": { "resourceType": "KEY_PERSON", "resourceId": 12 }, "roles": [{ "role": "DIRECTOR" }] } ``` Use incorporation participant and document endpoints for incorporation-specific roles and documents. This endpoint only creates the reusable person record. ## Person addresses Some incorporation requirements validate fields on the referenced person resource. For Singapore individual directors and shareholders, `participants.{participantId}.resource.residentialAddress` is satisfied by setting `residentialAddress` on the person: ```json theme={null} { "firstName": "Jane", "lastName": "Tan", "email": "jane@example.com", "dateOfBirth": "1990-04-18", "countryOfCitizenship": "SG", "residentialAddress": { "addressLine1": "1 Raffles Place", "city": "Singapore", "postalCode": "048616", "country": "SG" } } ``` This stores the address on the person. Person read responses return it as the top-level `residentialAddress` field. It does not create a Commenda OS Location; Location resources are business-entity addresses, such as a partner-provided registered office address. # Update a person Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-persons-id-PATCH PATCH /partner/commenda-os/customers/{customerId}/persons/{personId} Partially update a reusable Commenda OS person. Omitted fields are left unchanged. For Singapore residential address requirements, include `residentialAddress`. Partially update a reusable Commenda OS person for one of your customers. Omitted fields are left unchanged. The response returns the updated person. Use incorporation participant and document endpoints for incorporation-specific roles and documents. ## Residential address Some incorporation requirements validate fields on the referenced person resource. For Singapore individual directors and shareholders, `participants.{participantId}.resource.residentialAddress` is satisfied by updating the referenced person with the top-level `residentialAddress` field. ```json theme={null} { "residentialAddress": { "addressLine1": "1 Raffles Place", "city": "Singapore", "postalCode": "048616", "country": "SG" } } ``` This stores the address on the person. Person read responses return it as the top-level `residentialAddress` field. It does not create a Commenda OS Location; Location resources are business-entity addresses, such as a partner-provided registered office address. # List supported registrations Source: https://docs.commenda.io/engine/commendaos/partner-api/commenda-os-registrations-supported-GET GET /partner/commenda-os/registrations/supported List the registrations Commenda OS supports globally. Returns the full catalog of registration types that Commenda OS supports across all jurisdictions and entity types. Use this endpoint to discover which registrations are available before querying a specific business entity. Each entry in the response includes the registration's display name, jurisdiction, applicable entity type, purpose (for example, formation or tax), and whether the registration expires. # List companies Source: https://docs.commenda.io/engine/incorporation/companies-GET GET /public/companies List companies visible to the authenticated legacy affiliate API key. Lists companies visible to the authenticated legacy affiliate API key. A company is the Commenda account-level container for the customer you are onboarding. It is not the incorporated legal entity itself. Partner API callers should use [List customers](/engine/partner-api/customers-GET). # Create a company Source: https://docs.commenda.io/engine/incorporation/company-POST POST /public/company Create a new company container for legacy affiliate workflows. Creates a new company for incorporation and entity management workflows. A company is the Commenda account-level container for the customer you are onboarding. It is not the incorporated legal entity itself. Partner API callers should use [Create a customer](/engine/partner-api/customers-POST), which returns `customerId` for incorporation and Commenda OS calls. After creating the company, call `GET /partner/incorporation/jurisdiction-catalog` and `GET /partner/incorporation/requirements` to choose the incorporation jurisdiction and understand the required data. # List company documents (deprecated) Source: https://docs.commenda.io/engine/incorporation/documents-GET GET /public/documents Deprecated. Use the Commenda OS documents endpoints instead. This endpoint is deprecated and will be removed. Use [List documents](/engine/commendaos/partner-api/commenda-os-business-entities-id-documents-GET) and [List supported document types](/engine/commendaos/partner-api/commenda-os-business-entities-id-documents-supported-GET) in the Commenda OS Partner API instead. # Get a file download URL Source: https://docs.commenda.io/engine/incorporation/file-id-GET GET /public/file/{fileId} Return a temporary download URL for a file the authenticated affiliate can access. Returns a temporary download URL for a file the authenticated affiliate can access. # Incorporation API Source: https://docs.commenda.io/engine/incorporation/introduction Create affiliate-scoped companies and incorporation services, then track the resulting payment-intent and document flow. ## Overview This API surface is authenticated with an affiliate `x-api-key` and scoped to the companies your affiliate firm can access. Base URL: ```text theme={null} https://api.prod.commenda.io/api/v1/public ``` ## Authentication Pass your affiliate API key in the `x-api-key` header on every request. ```bash theme={null} curl --request GET \ --url 'https://api.prod.commenda.io/api/v1/public/payment-intents' \ --header 'x-api-key: ' ``` ## Current Flow 1. Create a company with `POST /public/company`. 2. Start an incorporation service with `POST /public/services`. 3. Poll payment intent and service status with the payment-intent endpoints. 4. Use the Commenda OS documents endpoints for document retrieval. 5. Download a concrete file with `GET /public/file/{fileId}`. ## Contract notes * Access is resolved through affiliate-firm ownership, not end-user login. * `POST /public/services` only accepts [supported incorporation service types](/engine/incorporation/services-POST). Unsupported types return `400 Bad Request`. * `POST /public/services` returns a `paymentIntentId`, which is the current public anchor for the flow. * Filtering payment intents by `companyId` enforces affiliate ownership — requests for companies outside your affiliate return `403 Forbidden`. * `GET /public/documents` is deprecated. Callers should use the Commenda OS documents endpoints instead. ## Partner Incorporation API New partner integrations that need an incorporation resource lifecycle can use the [Partner Incorporation API](/engine/incorporation/partner-incorporation-introduction). That surface is scoped under `/partner/incorporation`, creates incorporations directly under a company, and does not create or return payment intents. ## Commenda OS Partner API A separate Commenda OS Partner API is available under the `/partner/commenda-os` base URL. * See [Commenda OS Partner API](/engine/commendaos/partner-api/commenda-os-introduction) for business-entity, persons, documents, and registrations endpoints. * Use [List documents](/engine/commendaos/partner-api/commenda-os-business-entities-id-documents-GET) and [List supported document types](/engine/commendaos/partner-api/commenda-os-business-entities-id-documents-supported-GET) instead of the deprecated `GET /public/documents` route. # Build an incorporation flow Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-build-flow Implement a customer incorporation workflow from customer creation through final submit for review. This guide shows the recommended implementation sequence for a customer incorporation flow. Use [Core concepts](/engine/incorporation/partner-incorporation-core-concepts) for the object model and the endpoint reference pages for exact request and response schemas. ## Minimum happy path 1. Create or find the customer record and save `customerId`. 2. Read the jurisdiction catalog, choose `country` plus `countryOptions`, and fetch the requirements schema. 3. Create the incorporation and save `incorporation.id`. 4. Create or reuse required Commenda OS records, such as people, business entities, locations, and documents. 5. Register participants and upsert required participant documents. 6. Submit incorporation-level intake fields, then read validation until `incorporationValidation.isComplete` is `true`. 7. Submit for review, then track status and active issues. ## Detailed implementation sequence | Phase | Developer question | What to do | | -------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Setup | What record owns the work? | Create a customer and save `customerId`. | | Jurisdiction catalog | What can I incorporate? | Read the jurisdiction catalog and choose `country` plus `countryOptions`. | | Requirements | What data do I need? | Fetch the requirements schema for the selected jurisdiction/type. | | Progress setup | How will progress display? | Fetch the status workflow for the selected incorporation type. | | Incorporation | How do I start the incorporation? | Create the incorporation and save `incorporation.id`. | | Add customer records | What reusable records must exist? | Create or reuse Commenda OS people, business entities, and locations. | | Participants | Who is involved? | Register reusable people/entities as directors and shareholders. | | Documents | How do I attach files? | Follow [Upload files for incorporation](/engine/incorporation/partner-incorporation-document-upload-flow): upload customer files with multipart form data to obtain `fileId`, then upsert each file as a typed participant document. | | Intake | What non-participant fields are needed? | Submit partial or complete intake updates. | | Submit for review | How do I hand it to Commenda? | Read validation, call the submit endpoint when `incorporationValidation.isComplete` is `true`, then track `GET /partner/incorporation/{incorporationId}/status`. | | Issues | What if Commenda needs corrections? | Read active/resolved issues, update the underlying intake/participants/documents, and optionally receive issue webhooks. Active issues set top-level status to `BLOCKED`. | ## IDs you'll save | ID | Returned by | Used in | Notes | | ---------------------------- | -------------------------------------------------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `customerId` | `POST /partner/customers` as `customer.id` | Create incorporation; Commenda OS customer-scoped endpoints | Numeric customer id. | | `incorporation.id` | Create/list/get incorporation | Participants, documents, intake, direct read route | Use this as `{incorporationId}`. | | `businessEntityId` | Create/list/get incorporation | Commenda OS business-entity endpoints for the entity being incorporated | Target business entity id for the entity being incorporated. For new Partner API incorporations, this is returned on create. It is different from corporate shareholder `businessEntity.id` values. | | Person `id` | `POST /partner/commenda-os/customers/{customerId}/persons` | Participant `resource.resourceId` | Send as a number, for example `12`. | | Business entity `id` | `POST /partner/commenda-os/customers/{customerId}/business-entities` | Corporate participant `resource.resourceId` | Send as a number, for example `44`. | | Participant `id` | Register participant | Update participant roles; upsert participant documents | Incorporation-scoped participant id. | | `fileId` | `POST /partner/commenda-os/customers/{customerId}/files` | Upsert participant document | Customer-scoped file id returned after multipart upload. | | `documentId` | Upsert participant document | Read/list participant state | Incorporation-scoped typed document link. | | `statusWorkflow.stages[].id` | Status workflow or incorporation status | Progress UI and issue-stage correlation | Stage ids come from the active workflow definition. | | `issue.id` | List issues or issue webhook payload | Dedupe issue webhooks; correlate correction requests | One issue row represents one remediation episode. | | `webhookSubscription.id` | Create/list webhook subscriptions | Read or delete webhook subscription | Partner-level subscription, not scoped to one customer. | ## Happy path: Singapore private limited company This example uses one individual as both director and shareholder. ```text theme={null} customerId = 77 personId = 12 incorporationId = 0f9a8f5e-7f7c-4c1b-a60a-b1022f9d8c91 participantId = participant_123 passportFileId = 456 utilityBillFileId = 789 ``` ### 1. Create the customer ```bash theme={null} curl --request POST \ --url 'https://api.prod.commenda.io/api/v1/partner/customers' \ --header 'content-type: application/json' \ --header 'x-api-key: ' \ --data '{ "email": "owner@example.com", "name": "Acme Singapore" }' ``` Save the returned `customerId`. ### 2. Choose jurisdiction and fetch requirements ```bash theme={null} curl --request GET \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/jurisdiction-catalog' \ --header 'x-api-key: ' ``` For Singapore private limited company requirements: ```bash theme={null} curl --request GET \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/requirements?country=SG&countryOptions[corporationType]=PRIVATE_LIMITED_COMPANY' \ --header 'x-api-key: ' ``` For the public progress stages: ```bash theme={null} curl --request GET \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/status-workflow?country=SG&countryOptions[corporationType]=PRIVATE_LIMITED_COMPANY' \ --header 'x-api-key: ' ``` Render your UI from the returned requirements schema, but treat the server response as informational. Commenda validates every intake update against the current server-side requirements. ### 3. Create the incorporation ```bash theme={null} curl --request POST \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/customers/77/incorporations' \ --header 'content-type: application/json' \ --header 'x-api-key: ' \ --data '{ "country": "SG", "countryOptions": { "corporationType": "PRIVATE_LIMITED_COMPANY" } }' ``` Save `incorporation.id`. The initial `incorporationStatus` is usually `AWAITING_CUSTOMER_INPUT`. ### 4. Create or reuse a person If the director/shareholder does not already exist in Commenda OS, create a reusable person: ```bash theme={null} curl --request POST \ --url 'https://api.prod.commenda.io/api/v1/partner/commenda-os/customers/77/persons' \ --header 'content-type: application/json' \ --header 'x-api-key: ' \ --data '{ "firstName": "Jane", "lastName": "Founder", "email": "jane@example.com", "dateOfBirth": "1990-04-18", "countryOfCitizenship": "SG" }' ``` Save the returned person `id`. When you register the participant, send it as a number in `resource.resourceId`. ### 5. Register participants and roles For Singapore private limited companies, use this role/type matrix: | Participant scenario | `participantType` | `resource.resourceType` | Supported role payload | | ---------------------- | ----------------- | ----------------------- | ---------------------------------------------------------- | | Individual director | `INDIVIDUAL` | `KEY_PERSON` | `{ "role": "DIRECTOR" }` | | Individual shareholder | `INDIVIDUAL` | `KEY_PERSON` | `{ "role": "SHAREHOLDER", "ownershipPercentage": number }` | | Corporate shareholder | `CORPORATE` | `BUSINESS_ENTITY` | `{ "role": "SHAREHOLDER", "ownershipPercentage": number }` | | Corporate director | `CORPORATE` | `BUSINESS_ENTITY` | Not supported. | ```bash theme={null} curl --request POST \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/0f9a8f5e-7f7c-4c1b-a60a-b1022f9d8c91/participants' \ --header 'content-type: application/json' \ --header 'x-api-key: ' \ --data '{ "participantType": "INDIVIDUAL", "resource": { "resourceType": "KEY_PERSON", "resourceId": 12 }, "roles": [ { "role": "DIRECTOR" }, { "role": "SHAREHOLDER", "ownershipPercentage": 40 } ] }' ``` For Singapore private limited companies, registered shareholder participant `ownershipPercentage` values must total 100. Participant writes that would make shareholder ownership exceed 100 are rejected; totals below 100 are accepted while the customer is still entering shareholders, but validation remains incomplete until the total equals 100. If the shareholder is a company, create or reuse a Commenda OS business entity first: ```bash theme={null} curl --request POST \ --url 'https://api.prod.commenda.io/api/v1/partner/commenda-os/customers/77/business-entities' \ --header 'content-type: application/json' \ --header 'x-api-key: ' \ --data '{ "incorporationCountry": "SG", "legalName": "Acme Holdings Pte. Ltd.", "jurisdiction": "JUR_SG__GENERAL", "corporationType": "PteLtd" }' ``` Then register it as a corporate shareholder: ```bash theme={null} curl --request POST \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/0f9a8f5e-7f7c-4c1b-a60a-b1022f9d8c91/participants' \ --header 'content-type: application/json' \ --header 'x-api-key: ' \ --data '{ "participantType": "CORPORATE", "resource": { "resourceType": "BUSINESS_ENTITY", "resourceId": 44 }, "roles": [ { "role": "SHAREHOLDER", "ownershipPercentage": 60 } ] }' ``` To correct roles or ownership after registration, send the full desired roles array for that participant: ```bash theme={null} curl --request PATCH \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/0f9a8f5e-7f7c-4c1b-a60a-b1022f9d8c91/participants/participant_123' \ --header 'content-type: application/json' \ --header 'x-api-key: ' \ --data '{ "roles": [ { "role": "DIRECTOR" }, { "role": "SHAREHOLDER", "ownershipPercentage": 40 } ] }' ``` ### 6. Upload and upsert documents Upload each source document as multipart form data to create a reusable customer file. Upserting the participant document assigns that file to the participant document slot without changing the reusable file. The multipart upload endpoint lives in the Commenda OS Partner API because files are reusable customer resources. For a shorter file-upload walkthrough, see [Upload files for incorporation](/engine/incorporation/partner-incorporation-document-upload-flow). ```bash theme={null} curl --request POST \ --url 'https://api.prod.commenda.io/api/v1/partner/commenda-os/customers/77/files' \ --header 'x-api-key: ' \ --form 'file=@./passport.pdf;type=application/pdf' curl --request POST \ --url 'https://api.prod.commenda.io/api/v1/partner/commenda-os/customers/77/files' \ --header 'x-api-key: ' \ --form 'file=@./utility-bill.pdf;type=application/pdf' ``` Then upsert each file as a typed participant document: ```bash theme={null} curl --request PUT \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/0f9a8f5e-7f7c-4c1b-a60a-b1022f9d8c91/participants/participant_123/documents/PASSPORT_SCAN' \ --header 'content-type: application/json' \ --header 'x-api-key: ' \ --data '{ "fileId": 456 }' curl --request PUT \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/0f9a8f5e-7f7c-4c1b-a60a-b1022f9d8c91/participants/participant_123/documents/UTILITY_BILL' \ --header 'content-type: application/json' \ --header 'x-api-key: ' \ --data '{ "fileId": 789 }' ``` For Singapore private limited companies, every individual director and individual shareholder needs both `PASSPORT_SCAN` and `UTILITY_BILL`. ### 7. Submit intake data Intake updates are merge-based and may be partial. Use this endpoint for incorporation details such as company name options and registered office address choice. ```bash theme={null} curl --request PATCH \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/0f9a8f5e-7f7c-4c1b-a60a-b1022f9d8c91/intake' \ --header 'content-type: application/json' \ --header 'x-api-key: ' \ --data '{ "requirements": { "companyNameOptions": [ { "name": "Acme SG Pte. Ltd." }, { "name": "Acme Asia Pte. Ltd." }, { "name": "Acme Global Pte. Ltd." } ], "registeredOfficeAddressSource": "commendaService" } }' ``` ### 8. Check readiness to submit ```bash theme={null} curl --request GET \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/0f9a8f5e-7f7c-4c1b-a60a-b1022f9d8c91/validation' \ --header 'x-api-key: ' ``` Check `incorporationValidation.isComplete`. When it is `true`, the incorporation is eligible to submit for Commenda review. ### 9. Submit for review ```bash theme={null} curl --request POST \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/0f9a8f5e-7f7c-4c1b-a60a-b1022f9d8c91/submit' \ --header 'x-api-key: ' ``` The submit endpoint refreshes validation before accepting the handoff. If the incorporation is incomplete, it returns `400` with validation details. If it succeeds, Commenda begins review. The response usually returns `incorporationStatus: "IN_PROGRESS"` once review starts. ### 10. Track status ```bash theme={null} curl --request GET \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/0f9a8f5e-7f7c-4c1b-a60a-b1022f9d8c91/status' \ --header 'x-api-key: ' ``` Use this response for customer-facing progress. It includes the top-level `incorporationStatus`, ordered `stages`, and active `blockingIssueIds`. ## Requirements guide | Requirements area | What it means | How to use it | | --------------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | | `blocks` | UI-friendly groups of fields | Render fields by block if you want a guided UI. | | `fields` | Incorporation-level data, such as company names or registered office address choice | Submit these keys under `requirements` in the intake endpoint. | | `required.when` / `appliesWhen` | Rules that make a field required or applicable only when another field has a value | Re-evaluate the UI when the controlling field changes. Non-applicable fields are ignored by validation. | | `participantRequirements` | Required roles such as director or shareholder | Satisfy these by registering participants, not by sending arrays in intake. | | `resourceFieldsByParticipantType` | Required fields on a participant's referenced Commenda OS resource | Complete these fields on the person or business entity before submitting. | | `documentRequirements` | Required typed documents for a participant role/type | Satisfy these by upserting customer files as participant documents. | | Version fields | Requirements version metadata | Store these in logs for debugging. Do not send them back or gate UI behavior on exact values. | Validation issues use paths that point to the missing or invalid requirement. | Example path | Meaning | Fix | | -------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `companyNames.companyNameOptions` | Company name options are missing or invalid | Submit valid names through the intake endpoint as `requirements.companyNameOptions`. | | `registeredOfficeAddress.registeredOfficeAddressLocation` | A partner-provided registered office address location is required | Submit a Commenda OS location reference as `requirements.registeredOfficeAddressLocation` or choose `commendaService`, which means Commenda should provide the registered office address service. | | `registeredOfficeAddress.registeredOfficeAddressLocation.resourceId` | The referenced registered office address location is missing or inaccessible | Use a Commenda OS location for the same customer record as the incorporation, create or update the location through the Commenda OS Partner API, or choose `commendaService`. | | `participants.directors` | A required director participant is missing | Register a person or business entity as a director. | | `participants.participant_123.resource.lastName` | A referenced participant resource is missing a required field | Update the reusable Commenda OS person or business entity, then reread the incorporation validation. | | `participants.participant_123.resource.residentialAddress` | A Singapore individual director or shareholder is missing a residential address | Update the Commenda OS person with `residentialAddress: { ... }`. | | `participants.participant_123.documents.PASSPORT_SCAN` | A participant is missing a passport scan | Upload a customer file, then upsert it as `PASSPORT_SCAN` for that participant. | Fetch requirements after the user chooses a jurisdiction and corporation type. Render your UI from the requirements response, but decide readiness from validation returned by write/read calls because Commenda may update requirements over time. ## Completion semantics `incorporationValidation.isComplete` means the current data satisfies the incorporation requirements and is eligible to submit. It does not by itself hand the incorporation to Commenda. ```text theme={null} AWAITING_CUSTOMER_INPUT -> SUBMITTED after POST /partner/incorporation/{incorporationId}/submit succeeds and before Commenda review work starts -> IN_PROGRESS when Commenda review is in progress -> BLOCKED when there are active partner-visible issues or review start/runtime failures -> COMPLETED when the incorporation is complete ``` Correction requests are represented by read-only issues and surface as `BLOCKED` while active. ## Issues and correction requests Commenda can create partner-visible issues when an incorporation needs correction or additional information. ```bash theme={null} curl --request GET \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/0f9a8f5e-7f7c-4c1b-a60a-b1022f9d8c91/issues?status=ACTIVE' \ --header 'x-api-key: ' ``` Issues are read-only over the Partner API. To resolve them, fix the underlying data through the normal endpoints: update intake fields, register or update participants, upload and upsert replacement documents, or otherwise provide the requested information. Commenda resolves the issue after review. Each issue row represents one remediation episode. Resolved incorporation issues are not reopened; if the same kind of correction is needed again later, Commenda creates a new issue with a new `issue.id`. Active issues are also returned by the status endpoint as `blockingIssueIds`. If an issue scope includes `stageId`, that issue is attached to the matching stage's `blockedByIssueIds`; otherwise it blocks the first non-completed stage. Issue codes include `MISSING_INFORMATION`, `INVALID_INFORMATION`, `DOCUMENT_REQUIRED`, `DOCUMENT_INVALID`, `COMPANY_NAME_REJECTED`, and `OTHER`. Commenda may add additional issue codes in future API updates. ## Issue webhooks Subscribe to issue events if your integration should react without polling: ```bash theme={null} curl --request POST \ --url 'https://api.prod.commenda.io/api/v1/partner/webhook-subscriptions' \ --header 'content-type: application/json' \ --header 'x-api-key: ' \ --data '{ "url": "https://partner.example.com/commenda/webhooks", "eventTypes": [ "INCORPORATION_ISSUE_CREATED", "INCORPORATION_ISSUE_RESOLVED" ] }' ``` The create response includes the full signing secret once. Later reads return only `secretPreview`. Webhook delivery is asynchronous and retried. Your endpoint should respond within 10 seconds and dedupe deliveries by `eventId`. ## Common errors and fixes | Symptom | Likely cause | Fix | | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | `400` on create incorporation | Unsupported `countryOptions` or missing `countryOptions[corporationType]` | Fetch the jurisdiction catalog and use an advertised option value. | | `403` on customer-scoped call | The customer is not accessible to the partner API key | Check the `customerId` and API key. | | `404` when registering participant | The referenced person or business entity is not visible to the customer | Create or fetch the resource through Commenda OS first. | | `400` when registering or updating participant | Shareholder role is missing `ownershipPercentage`, role/resource type is unsupported, or ownership would exceed 100 | Follow the selected incorporation requirements and adjust existing shareholder roles before adding more ownership. | | Incomplete validation for shareholders | Ownership percentages do not total 100 | Update shareholder participant roles so totals equal 100. | | `400` when uploading customer file | Missing file part, unsupported MIME type, or file too large | Send exactly one binary `file` part and a supported file type. | | `404` when upserting document | The participant or file cannot be found | Register the participant and upload the customer file first. | | `400` when upserting document | File type is incompatible or the document kind is not required for this participant | Use a required `documentKind` from the requirements response and a compatible customer file. | | `400` for intake | Field value does not match the current incorporation requirements | Read `invalidRequirements` and update the field. | | `400` on submit | The current state is incomplete | Read the returned validation details or call `GET /partner/incorporation/{incorporationId}`, then fix missing/invalid requirements before retrying submit. | # Core concepts Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-core-concepts Understand the records, IDs, and API choices that make up a customer incorporation flow. ## Object model | Concept | What it means | Main ID | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | | Customer | One of your customers. Every resource in the incorporation API is scoped to a specific customer. | `customerId` | | Incorporation | A specific incorporation workflow, including selected jurisdiction/entity type. | `incorporation.id` | | Commenda OS reusable resource | Customer data that can be reused across workflows, such as people, business entities, locations, and files. | Resource-specific IDs | | Participant | A reference to a person or business entity in Commenda OS, attached to this incorporation with a role such as `DIRECTOR` or `SHAREHOLDER`. | `participant.id` | | Intake | A collection of user-provided information about the entity being incorporated, such as company name options and registered office address choice. | `intakeState` | | Status and issues | Post-submit progress and partner-visible correction requests. | `incorporationStatus`, `issue.id` | ```text theme={null} Customer -> Incorporation -> Participants -> Commenda OS people/business entities -> Participant documents -> Intake fields -> Status and issues ``` ## Reusable records vs incorporation-specific records People, business entities, locations, and files live in Commenda OS so customers can reuse them across KYC, entity management, registrations, and documents. The Incorporation API links those reusable records to a specific incorporation. | Need | Create or read in | Link through | | -------------------------------------------- | ----------------------------- | ---------------------------------------- | | Director or shareholder person | Commenda OS Persons | Incorporation Participants | | Corporate shareholder | Commenda OS Business Entities | Incorporation Participants | | Registered office location | Commenda OS Locations | Intake `registeredOfficeAddressLocation` | | Passport, utility bill, or other source file | Commenda OS Files | Participant document upsert | ## Which API to call | API surface | Use it for | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | Customer setup | Create or list the customer record that scopes later calls. | | Partner Incorporation API | Discover requirements, create incorporations, register participants, upsert participant documents, submit intake, track status, and read issues. | | Commenda OS Partner API | Manage reusable customer data such as people, business entities, locations, files, documents, government identifiers, and registrations. | | Partner webhooks | Subscribe to partner events such as incorporation issue creation and resolution. | ## What to read next * Start the implementation with [Build an incorporation flow](/engine/incorporation/partner-incorporation-build-flow). * Create or find a customer record with [Create a customer](/engine/partner-api/customers-POST) or [List customers](/engine/partner-api/customers-GET). * Use the [Commenda OS Partner API](/engine/commendaos/partner-api/commenda-os-introduction) when you need reusable customer records. # Upload files for incorporation Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-document-upload-flow Attach customer files to incorporation document requirements. Use this flow when a customer needs to provide files such as passport scans, utility bills, or corporate documents for an incorporation. Incorporation documents are built from reusable Commenda OS files. The file upload endpoint lives in the [Commenda OS Partner API](/engine/commendaos/partner-api/commenda-os-introduction) because files can be reused outside incorporation for KYC, entity records, registrations, and customer file attachments. The Incorporation API takes the resulting `fileId` and assigns it to a participant document slot. ## Flow 1. Upload the file with [Upload a file](/engine/commendaos/partner-api/commenda-os-files-POST), sending the bytes as `multipart/form-data`. Save the returned `file.fileId`. 2. Upsert the `fileId` into a participant document slot with [Upsert a participant document](/engine/incorporation/partner-incorporation-participant-documents-PUT). ## Endpoint map | Step | Endpoint | API surface | Output | | --------------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------- | --------------------- | | Upload file | `POST /partner/commenda-os/customers/{customerId}/files` | Commenda OS Partner API | `file.fileId` | | Upsert typed participant document | `PUT /partner/incorporation/{incorporationId}/participants/{participantId}/documents/{documentKind}` | Partner Incorporation API | `document.documentId` | ## Important handoffs * The upload endpoint accepts only a `file` multipart part. It returns a `fileId` and nothing else — any metadata set by future attach calls is layered on top of the underlying file. * Use `file.fileId` when upserting incorporation participant documents. The upsert assigns the file to the participant document slot. * Uploads are capped at 100 MB per request, must use one of the accepted MIME types, and time out after 120 seconds. See [Upload a file](/engine/commendaos/partner-api/commenda-os-files-POST) for the full limits and error codes. Contact Commenda if you need to upload files larger than 100 MB. # List incorporations Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-incorporations-GET GET /partner/incorporation/customers/{customerId}/incorporations List incorporations visible to the authenticated partner for a single customer. Lists incorporations for one of your customers. Use `limit` and `offset` for pagination. The `count` field is the total number of matching incorporations before pagination. ## Incorporation status Each returned incorporation includes `incorporationStatus`: | Status | Meaning | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `AWAITING_CUSTOMER_INPUT` | Required intake information, participant roles, or documents are still missing or invalid, or the current state is complete but has not been submitted for review. | | `SUBMITTED` | The incorporation was explicitly submitted and currently validates against the incorporation requirements, but Commenda review has not started yet. | | `IN_PROGRESS` | Commenda review is in progress. | | `BLOCKED` | The incorporation has active partner-visible issues or review start/runtime failures. | | `COMPLETED` | The incorporation has been completed. | # Create an incorporation Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-incorporations-POST POST /partner/incorporation/customers/{customerId}/incorporations Begin an incorporation for one of your customers. Starts an incorporation for one of your customers. The response returns the incorporation resource directly, plus `incorporationValidation`, current requirements, and `intakeState`. If no initial intake values are supplied, `intakeState.currentState` is `{}`. For a complete Singapore walkthrough with the IDs to save, see [Build an incorporation flow](/engine/incorporation/partner-incorporation-build-flow). ## Request shape Create requests use a `country` plus country-specific `countryOptions` instead of a flat product id. * `country` is the ISO 3166-1 alpha-2 code for the jurisdiction. * `countryOptions` is an object whose shape depends on `country`. * `customerId` is the path parameter for the customer that owns the incorporation. * `intake.requirements` is optional and can contain initial partial intake data. * Unknown or unsupported options are rejected by this endpoint. ## Singapore example ```json theme={null} { "country": "SG", "countryOptions": { "corporationType": "PRIVATE_LIMITED_COMPANY" } } ``` Use `GET /partner/incorporation/jurisdiction-catalog` to see currently supported countries and option values. Use `GET /partner/incorporation/requirements` before building an intake UI. ## Initial partial intake example ```json theme={null} { "country": "SG", "countryOptions": { "corporationType": "PRIVATE_LIMITED_COMPANY" }, "intake": { "requirements": { "companyNameOptions": [ { "name": "Acme SG Pte Ltd" } ] } } } ``` ## Supported options | Country | Required options | Optional options | | ---------------- | --------------------------------------------------- | ----------------------------------------------------------------- | | `US` | `corporationType`: `CORPORATION`, `LLC` | `state`: US state abbreviation | | `CA` | `corporationType`: `CORPORATION` | None | | `IN` | `corporationType`: `LLP`, `PRIVATE_LIMITED_COMPANY` | None | | `AE` | `corporationType`: `FZC` | `corporationTypeOptions.freeZone`: `ADGM`, `DIFC`, `DMCC`, `IFZA` | | `GB`, `IE`, `NZ` | `corporationType`: `LIMITED_COMPANY` | None | | `KY` | `corporationType`: `EXEMPTED_COMPANY` | None | | `SG` | `corporationType`: `PRIVATE_LIMITED_COMPANY` | None | ## Response status New incorporations are returned with `incorporationStatus: "AWAITING_CUSTOMER_INPUT"`. Once required intake data, participant roles, and documents validate, call `POST /partner/incorporation/{incorporationId}/submit`; after submit succeeds, the status becomes `SUBMITTED` or `IN_PROGRESS` depending on workflow start state. # Get an incorporation Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-incorporations-id-GET GET /partner/incorporation/{incorporationId} Retrieve one incorporation visible to the authenticated partner. Use this direct route for intake state reads. Retrieves an incorporation for one of your customers. Use this endpoint to refresh the latest `intakeState`, participants, and top-level `incorporationStatus` for an ongoing incorporation. `incorporationValidation.isComplete` tells you whether the current state is eligible to submit. `SUBMITTED` or `IN_PROGRESS` is returned only after `POST /partner/incorporation/{incorporationId}/submit` succeeds for a currently complete incorporation. Use [Get incorporation status](/engine/incorporation/partner-incorporation-status-GET) for stage-level progress and blocking issue ids. Use [List incorporation issues](/engine/incorporation/partner-incorporation-issues-GET) to track active or resolved correction requests. ## Incorporation status `incorporationStatus` can be one of: | Status | Meaning | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `AWAITING_CUSTOMER_INPUT` | Required intake information, participant roles, or documents are still missing or invalid, or the current state is complete but has not been submitted for review. | | `SUBMITTED` | The incorporation was explicitly submitted and currently validates against the incorporation requirements, but Commenda review has not started yet. | | `IN_PROGRESS` | Commenda review is in progress. | | `BLOCKED` | The incorporation has active partner-visible issues or review start/runtime failures. | | `COMPLETED` | The incorporation has been completed. | # Update incorporation intake Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-intake-PATCH PATCH /partner/incorporation/{incorporationId}/intake Partially update incorporation intake details. Each write returns the updated intake state and incorporation validation summary. Use this endpoint to save the details required to prepare an incorporation, such as proposed company names, registered office address preference, share capital, and business activities. The available fields depend on the selected country and incorporation options. Each request can be partial. Include only the values you want to add or change in `requirements`. Commenda merges them into the current intake state, validates the full incorporation, and returns the updated `intakeState` plus `incorporationValidation`. The Partner API does not expose a submission history endpoint. To read progress after an update, call `GET /partner/incorporation/{incorporationId}` or `GET /partner/incorporation/{incorporationId}/validation`. The incorporation is ready to submit when `incorporationValidation.isComplete` is `true`. Call `POST /partner/incorporation/{incorporationId}/submit` to hand the incorporation to Commenda for review. Participant roles, participant resource fields, and participant documents are managed outside this intake payload. Register participant roles with the participant endpoints, complete required person or business entity fields through the Commenda OS Partner API, and upsert participant documents through the document endpoint. ## Accepted requirement keys `requirements` only accepts incorporation-level requirement keys defined under `blocks[].fields` in the [requirements response](/engine/incorporation/partner-incorporation-requirements-GET) for the current incorporation type. If you send a key that is not declared at the incorporation level, the request returns `400 Bad Request` with an `Unknown intake requirement key(s)` message and the intake state is not updated. This includes participant-shaped payloads such as `participants`, `directors`, `shareholders`, top-level `residentialAddress`, or a nested `resource` object. Submit those values through the appropriate endpoint instead: | Payload shape | Where to submit | | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Participant roles such as `directors` or `shareholders` | [Register an incorporation participant](/engine/incorporation/partner-incorporation-participants-POST) or [Update an incorporation participant](/engine/incorporation/partner-incorporation-participants-id-PATCH) | | Person resource fields such as `residentialAddress` | [Update a partner person](/engine/partner-api/conventions) using `PATCH /partner/commenda-os/customers/{customerId}/persons/{personId}` | | Participant documents such as `PASSPORT_SCAN` | [Upsert a participant document](/engine/incorporation/partner-incorporation-participant-documents-PUT) | This validation runs before the intake state is merged, so rejected payloads cannot leave stale participant-shaped values behind in `currentState`. ## Intake fields Use this endpoint for incorporation-level requirements such as company name options and registered office address choice. ### Company name options Submit preferred legal names under `companyNameOptions`. ```json theme={null} { "requirements": { "companyNameOptions": [ { "name": "Acme Holdings" }, { "name": "Acme Global" }, { "name": "Acme Ventures" } ] } } ``` ### Registered office address Most incorporations require a registered office address. Choose how that address should be satisfied with `registeredOfficeAddressSource`. | Source | Use when | Required fields | | ------------------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | | `commendaService` | Commenda should provide the registered office address service for this incorporation. | `registeredOfficeAddressSource` | | `partnerProvidedLocation` | You already have a Commenda OS location to use as the registered office address. | `registeredOfficeAddressSource` and `registeredOfficeAddressLocation` | Use `commendaService` when Commenda should provide the registered office address service: ```json theme={null} { "requirements": { "registeredOfficeAddressSource": "commendaService" } } ``` Use `partnerProvidedLocation` when you are providing a reusable Commenda OS location: ```json theme={null} { "requirements": { "registeredOfficeAddressSource": "partnerProvidedLocation", "registeredOfficeAddressLocation": { "mode": "existingResource", "resourceId": "location_001" } } } ``` The referenced location must be attached to a Commenda OS business entity on the same customer record as the incorporation. If the existing location is missing a field required by the current incorporation requirements, you can include supplemental `data` on the `existingResource` reference for incorporation validation. If you later switch `registeredOfficeAddressSource` back to `commendaService`, any previously submitted `registeredOfficeAddressLocation` value may remain in `currentState`, but it is no longer applicable and will not block validation. ## Validation notes Country-specific validation rules are determined by the current incorporation requirements. If a selected incorporation requires shareholder ownership totals, address details, participant resource fields, or participant documents, the response returns `missingRequirements` and `invalidRequirements` until the current incorporation state satisfies those rules. Example validation details: ```json theme={null} { "incorporationValidation": { "isComplete": false, "missingRequirements": [ { "code": "PARTICIPANT_REQUIRED", "path": "participants.directors", "message": "At least one director is required" } ], "invalidRequirements": [ { "code": "COMPANY_NAME_OPTIONS_INCOMPLETE", "path": "companyNames.companyNameOptions", "message": "Provide at least 3 company name options" } ] } } ``` For participant-specific requirements, register participants with roles and upsert documents to each participant: * Use `POST /partner/incorporation/{incorporationId}/participants` for director/shareholder roles. * Use `POST /partner/commenda-os/customers/{customerId}/persons` or `PATCH /partner/commenda-os/customers/{customerId}/persons/{personId}` for required person fields such as `residentialAddress`. * Use `PUT /partner/incorporation/{incorporationId}/participants/{participantId}/documents/{documentKind}` for participant document requirements. # Intake state object Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-intake-state-object Field reference for the current incorporation intake values. The intake state object represents the latest merged incorporation-level intake data for one incorporation. The intake state is not a submission history. Each intake update merges new values into `currentState`, and Commenda revalidates the resulting incorporation state against the current requirements. ## Attributes | Attribute | Type | Description | | ----------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | Unique identifier for this intake state record. | | `incorporationId` | string | Incorporation this intake state belongs to. Same value used as `{incorporationId}` in intake, participant, document, status, issue, and submit endpoints. | | `currentState` | object | Latest partner-submitted incorporation-level requirement values. Keys vary by the current requirements for the selected country and incorporation options. | | `createdAt` | string | ISO timestamp for when the intake state record was created. | | `updatedAt` | string | ISO timestamp for when the intake state record was last updated. | ## Current state values `currentState` contains the merged requirement values submitted through [Update incorporation intake](/engine/incorporation/partner-incorporation-intake-PATCH). The top-level `currentState` property is always returned, but the values inside it are requirements-driven. When writing intake data, send requirement values under the `requirements` request property. When reading intake state, Commenda returns those same requirement keys under `currentState`. For example, an incorporation type that requires company name options and a registered office address may use these paths: | Example read path | Matching write path | Description | | ---------------------------------------------- | ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | `currentState.companyNameOptions` | `requirements.companyNameOptions` | Preferred legal names for the company being incorporated. | | `currentState.registeredOfficeAddressSource` | `requirements.registeredOfficeAddressSource` | How the registered office address should be satisfied, such as `commendaService` or `partnerProvidedLocation`. | | `currentState.registeredOfficeAddressLocation` | `requirements.registeredOfficeAddressLocation` | Commenda OS location reference used when the registered office address source is `partnerProvidedLocation`. | Fetch [Get incorporation requirements](/engine/incorporation/partner-incorporation-requirements-GET) to see the fields for the selected incorporation type. Because updates are merge-based, `currentState` can contain previously submitted values that are no longer applicable after later choices. Treat `incorporationValidation` as the source of truth for whether the current incorporation can be submitted. ## Endpoints | Action | Endpoint | | -------------------------- | ------------------------------------------------------------------------------------------ | | Create with initial intake | [Create an incorporation](/engine/incorporation/partner-incorporation-incorporations-POST) | | Update intake | [Update incorporation intake](/engine/incorporation/partner-incorporation-intake-PATCH) | | Retrieve current state | [Get an incorporation](/engine/incorporation/partner-incorporation-incorporations-id-GET) | | Read validation | [Get incorporation validation](/engine/incorporation/partner-incorporation-validation-GET) | | Submit when complete | [Submit an incorporation](/engine/incorporation/partner-incorporation-submit-POST) | # Partner Incorporation API Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-introduction Incorporate entities for your customers. Share information, track incorporation status, and resolve issues. ## Overview Use this API to help customers complete an incorporation from intake through Commenda review. If you are implementing the flow for the first time, read [Core concepts](/engine/incorporation/partner-incorporation-core-concepts) first, then follow [Build an incorporation flow](/engine/incorporation/partner-incorporation-build-flow). Base URL: ```text theme={null} https://api.prod.commenda.io/api/v1/partner/incorporation ``` Pass your partner API key in the `x-api-key` header on every request. ```bash theme={null} curl --request GET \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/jurisdiction-catalog' \ --header 'x-api-key: ' ``` ## Object model Each incorporation is built from a few related records: ```text theme={null} Customer -> Incorporation -> Participants -> Commenda OS people/business entities -> Participant documents -> Intake fields -> Status and issues ``` The `customerId` identifies the customer that owns the work. It is not the legal entity being incorporated. The `incorporation.id` identifies the incorporation for that customer. Participants, documents, intake, status, and issues all attach to that incorporation. For the full object map, see [Core concepts](/engine/incorporation/partner-incorporation-core-concepts). ## Flow at a glance 1. Create or find the customer and save `customerId`. 2. Choose a jurisdiction and corporation type with the jurisdiction catalog. 3. Create the incorporation and save `incorporation.id`. 4. Create or reuse Commenda OS records for people, business entities, locations, and files. 5. Register participants and upsert required participant documents. 6. Submit incorporation-level intake fields and check `incorporationValidation.isComplete`. 7. Submit the incorporation for Commenda review, then track status and issues. For the endpoint-by-endpoint version, including a Singapore private limited company example, see [Build an incorporation flow](/engine/incorporation/partner-incorporation-build-flow). ## Commenda OS resources Reusable customer records live in the Commenda OS Partner API: people, business entities, locations, and files. The Incorporation API links those records to a specific incorporation when they are needed for roles, addresses, or documents. | Need | Create or read in | Link through | | -------------------------------------------- | ----------------------------- | ---------------------------------------- | | Director or shareholder person | Commenda OS Persons | Incorporation Participants | | Corporate shareholder | Commenda OS Business Entities | Incorporation Participants | | Registered office location | Commenda OS Locations | Intake `registeredOfficeAddressLocation` | | Passport, utility bill, or other source file | Commenda OS Files | Participant document upsert | ## Incorporation requirements Fetch requirements after the user chooses a jurisdiction and corporation type. The requirements response describes the current checklist and field contract for that incorporation type. Use it to render your own UI, but treat server validation as authoritative. Participant and document requirements are satisfied by registering participants and upserting participant documents. Incorporation-level fields, such as company name options and registered office address choice, are submitted through the intake endpoint. ## Status and issues `incorporationValidation.isComplete` means the current data is eligible to submit. It does not submit the incorporation by itself. After submit, use `GET /partner/incorporation/{incorporationId}/status` for customer-facing progress. Commenda may create partner-visible issues when an incorporation needs correction or additional information. Issues are read-only over the Partner API; fix the underlying data through intake, participants, or documents, and Commenda resolves the issue after review. # List incorporation issues Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-issues-GET GET /partner/incorporation/{incorporationId}/issues List partner-visible issues for an incorporation. Active issues are returned by default. Issues are read-only over the Partner API; fix the underlying intake, participant, or document data to resolve them. Lists partner-visible issues for an incorporation. Issues are created and resolved by Commenda. Partners use this endpoint to understand what needs attention, then update intake data, participants, or documents through the normal incorporation endpoints. There is no public issue mutation endpoint in this phase. By default this endpoint returns active issues only. Use `status=RESOLVED` for resolved issues or `status=ALL` for the full issue history. ## Correction cycle semantics Each issue row represents one remediation episode. If Commenda needs the same kind of correction again after a prior issue was resolved, Commenda creates a new issue instead of reopening the old issue. This keeps webhook delivery and partner reconciliation simple: * `issue.id` is stable for one correction episode. * `INCORPORATION_ISSUE_CREATED` is emitted when that episode starts. * `INCORPORATION_ISSUE_RESOLVED` is emitted once when that episode is resolved. Active issues make `incorporationStatus` return `BLOCKED`. Read [Get incorporation status](/engine/incorporation/partner-incorporation-status-GET) to see which issues are currently blocking the incorporation and, when Commenda has assigned a stage, which stage they block. ## Issue codes Current issue codes: | Code | Meaning | | ----------------------- | ------------------------------------------------------------- | | `MISSING_INFORMATION` | Required information is missing. | | `INVALID_INFORMATION` | Submitted information is present but invalid or inconsistent. | | `DOCUMENT_REQUIRED` | A required participant document has not been provided. | | `DOCUMENT_INVALID` | A participant document file could not be accepted. | | `COMPANY_NAME_REJECTED` | A proposed company name was rejected or cannot be used. | | `OTHER` | General issue not covered by a more specific code. | Commenda may add additional issue codes in future API updates. Avoid hard-coding business logic that assumes this list is permanently exhaustive. ## Issue scopes `scope` tells you where the issue applies. | Scope type | Meaning | | ---------------------- | ------------------------------------------------------------------------------------------------ | | `INCORPORATION` | The issue applies to the overall incorporation. | | `INTAKE_FIELD` | The issue applies to an intake field validation path, such as `companyNames.companyNameOptions`. | | `PARTICIPANT` | The issue applies to a registered participant. | | `PARTICIPANT_DOCUMENT` | The issue applies to a participant document kind or linked file. | | `FILE` | The issue applies to an uploaded customer file used for the incorporation. | Scopes may also include `stageId`. When present, it matches a stage returned by the status workflow and is used to attach the issue to that stage in the status response. Example response: ```json theme={null} { "issues": [ { "id": "issue_123", "code": "DOCUMENT_INVALID", "message": "The passport scan for Jane Founder is unreadable. Please upload a clearer scan.", "status": "ACTIVE", "scope": { "type": "PARTICIPANT_DOCUMENT", "stageId": "kyc", "participantId": "participant_123", "documentKind": "PASSPORT_SCAN", "fileId": 456 }, "createdAt": "2026-04-25T20:58:00.000Z", "updatedAt": "2026-04-25T20:59:00.000Z" } ], "count": 1 } ``` # List jurisdiction catalog Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-jurisdiction-catalog-GET GET /partner/incorporation/jurisdiction-catalog Retrieve the informational catalog of supported incorporation countries and country-specific options. This endpoint helps clients render valid choices, but the create endpoint remains the source of truth for validation. Returns the currently supported incorporation countries and country-specific option fields. Use this endpoint as an informational catalog for rendering choices in your UI. The create incorporation endpoint remains the source of truth for validation. Field keys map directly to paths inside `countryOptions`. Simple keys become direct properties, such as `countryOptions.corporationType`. Dotted keys, such as `corporationTypeOptions.freeZone`, represent nested objects inside `countryOptions`. ## Supported countries The catalog currently includes `AE`, `CA`, `GB`, `IE`, `IN`, `KY`, `NZ`, `SG`, and `US`. ## Field format Each country returns a list of fields: ```json theme={null} { "country": "US", "fields": [ { "key": "state", "type": "select", "required": false, "options": ["AL", "AK", "AZ"] }, { "key": "corporationType", "type": "select", "required": true, "options": ["CORPORATION", "LLC"] } ] } ``` Use `key` as the path inside `countryOptions`. For example, `corporationTypeOptions.freeZone` should be sent as: ```json theme={null} { "countryOptions": { "corporationTypeOptions": { "freeZone": "DMCC" } } } ``` For Singapore private limited companies, the catalog returns a simple `corporationType` field: ```json theme={null} { "country": "SG", "fields": [ { "key": "corporationType", "type": "select", "required": true, "options": ["PRIVATE_LIMITED_COMPANY"] } ] } ``` Send that selection in `countryOptions` as: ```json theme={null} { "country": "SG", "countryOptions": { "corporationType": "PRIVATE_LIMITED_COMPANY" } } ``` For GET endpoints that use query parameters, send the same shape with deep-object query syntax: ```text theme={null} GET /partner/incorporation/requirements?country=SG&countryOptions[corporationType]=PRIVATE_LIMITED_COMPANY ``` This endpoint is informational only. It is safe to use for UI rendering, but clients should still handle validation errors from `POST /partner/incorporation/customers/{customerId}/incorporations`. # Jurisdiction catalog Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-jurisdiction-catalog-guide Use the catalog to show which incorporation options are currently available. The jurisdiction catalog is the first step in an incorporation flow. It tells your integration which countries are currently supported and which country-specific options the customer must choose before you can fetch requirements or create an incorporation. Use it to render the customer's initial choice of jurisdiction and entity type. ## What the catalog answers | Question | Catalog field | How to use it | | ----------------------------------------------- | --------------------- | ------------------------------------------------------- | | Which countries can my customer incorporate in? | `countries[].country` | Show available country choices. | | Which country-specific options are needed? | `countries[].fields` | Render the option fields for the selected country. | | Which values are accepted? | `fields[].options` | Restrict selections to the returned values. | | How do I send the selected options? | `fields[].key` | Build the `countryOptions` object using each field key. | ## Country options Each field key maps to a path inside `countryOptions`. Simple keys become direct properties: ```json theme={null} { "country": "SG", "countryOptions": { "corporationType": "PRIVATE_LIMITED_COMPANY" } } ``` Dotted keys represent nested objects: ```json theme={null} { "countryOptions": { "corporationTypeOptions": { "freeZone": "DMCC" } } } ``` For GET endpoints, send the same shape with deep-object query syntax: ```text theme={null} GET /partner/incorporation/requirements?country=SG&countryOptions[corporationType]=PRIVATE_LIMITED_COMPANY ``` ## When to refetch The catalog is informational and may change as Commenda adds jurisdictions or supported entity types. You can cache it for UI rendering, but your integration should still handle validation errors from create and requirements endpoints. After the customer selects `country` and `countryOptions`, use that selection to fetch: | Next step | Endpoint | | -------------------------------------------- | ------------------------------------------------------------------- | | Required fields, participants, and documents | `GET /partner/incorporation/requirements` | | Public progress stages | `GET /partner/incorporation/status-workflow` | | New incorporation | `POST /partner/incorporation/customers/{customerId}/incorporations` | # Incorporation object Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-object Field reference for the top-level Partner Incorporation API record. The incorporation object represents one customer incorporation. Create it after the customer chooses a jurisdiction and incorporation type, then use its `id` as `{incorporationId}` for participant, document, intake, status, issue, and submit endpoints. ## Attributes | Attribute | Type | Description | | --------------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | Unique incorporation identifier. Use this value as `{incorporationId}`. | | `customerId` | integer | Customer that owns the incorporation. This is not the legal entity being incorporated. | | `country` | string | ISO 3166-1 alpha-2 jurisdiction code for the incorporation. | | `countryOptions` | object | Country-specific incorporation selections. The shape depends on `country`; use the jurisdiction catalog to discover supported keys and values. | | `incorporationStatus` | string | Top-level lifecycle status for the incorporation. | | `businessEntityId` | integer or null | Target Commenda OS business entity id for the entity being incorporated. Corporate shareholder business entity ids are separate participant resource ids. | | `createdAt` | string | ISO timestamp for when the incorporation was created. | | `updatedAt` | string | ISO timestamp for when the incorporation was last updated. | ## Status values | Value | Meaning | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `AWAITING_CUSTOMER_INPUT` | Required intake information, participant roles, or documents are missing or invalid, or the current state is complete but has not been submitted for review. | | `SUBMITTED` | The incorporation was explicitly submitted and currently validates against the incorporation requirements, but workflow work has not started yet. | | `IN_PROGRESS` | Commenda is actively processing the incorporation through the dedicated workflow. | | `BLOCKED` | The incorporation has active partner-visible issues or workflow start/runtime failures. | | `COMPLETED` | The incorporation has been completed. | ## Related response data Some endpoints return the incorporation object inside a response wrapper with related data: | Field | Description | | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | `requirements` | Current incorporation requirements for the selected jurisdiction and options. | | `incorporationValidation` | Current validation result for the full incorporation. | | `intakeState` | Current submitted incorporation-level intake values. Always returned; an empty intake state is initialized automatically when one does not yet exist. | | `participants` | Participants registered to this incorporation, when requested or available. | ## Endpoints | Action | Endpoint | | ----------- | ------------------------------------------------------------------------------------------ | | Create | [Create an incorporation](/engine/incorporation/partner-incorporation-incorporations-POST) | | List | [List incorporations](/engine/incorporation/partner-incorporation-incorporations-GET) | | Retrieve | [Get an incorporation](/engine/incorporation/partner-incorporation-incorporations-id-GET) | | Submit | [Submit an incorporation](/engine/incorporation/partner-incorporation-submit-POST) | | Read status | [Get incorporation status](/engine/incorporation/partner-incorporation-status-GET) | | Read issues | [List incorporation issues](/engine/incorporation/partner-incorporation-issues-GET) | # Upsert a participant document Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-participant-documents-PUT PUT /partner/incorporation/{incorporationId}/participants/{participantId}/documents/{documentKind} Assign a customer-scoped Commenda file to one participant document slot. This request creates or replaces the typed participant document in one transaction without changing the reusable file. Repeating the request with the same fileId is safe. Assigns a customer-scoped Commenda file to one participant document slot. Use this endpoint after uploading a customer file with the Commenda OS Partner API. Commenda creates or replaces the typed participant document in one transaction without changing the reusable file. There is no separate file registration call. If you are starting from a passport scan, utility bill, or other local file, first follow [Upload files for incorporation](/engine/incorporation/partner-incorporation-document-upload-flow) to upload the file and get a `file.fileId`. The slot is replacement-based by `participantId` and `documentKind`. Calling this endpoint again with a different `fileId` replaces the file for that participant document. Calling it again with the same `fileId` is safe. The `documentKind` path value comes from the incorporation requirements. Current values include `PASSPORT_SCAN` and `UTILITY_BILL`. ```json theme={null} { "fileId": 456 } ``` # Participant object Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-participant-object Field reference for an incorporation-specific participant registration. The participant object represents a reusable Commenda OS person or business entity registered to one incorporation. The participant stores incorporation-specific roles, ownership data, and linked participant documents. It does not duplicate or replace the underlying Commenda OS resource. ## Attributes | Attribute | Type | Description | | ----------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | Incorporation-specific participant identifier. Use this value as `{participantId}` when updating or removing the participant. | | `participantType` | string | Whether the participant represents an `INDIVIDUAL` or `CORPORATE` participant. | | `resource` | object | Pointer to the reusable Commenda OS resource represented by this participant. | | `resource.resourceType` | string | Type of reusable resource. Supported values are `KEY_PERSON` and `BUSINESS_ENTITY`. | | `resource.resourceId` | integer | Numeric Commenda OS identifier. For `KEY_PERSON`, use a Commenda OS person id. For `BUSINESS_ENTITY`, use a Commenda OS business entity id. | | `roles` | array | Incorporation roles assigned to this participant. | | `documents` | array | Participant document links attached to this participant. | ## Participant types | Value | Meaning | | ------------ | ---------------------------------------------------------------------------------------------- | | `INDIVIDUAL` | A natural person registered to the incorporation through a Commenda OS person resource. | | `CORPORATE` | A legal entity registered to the incorporation through a Commenda OS business entity resource. | ## Resource types | Value | Use with | Description | | ----------------- | ------------------------------- | --------------------------------------------------------------------------------- | | `KEY_PERSON` | `participantType: "INDIVIDUAL"` | References a person created or read through the Commenda OS Partner API. | | `BUSINESS_ENTITY` | `participantType: "CORPORATE"` | References a business entity created or read through the Commenda OS Partner API. | ## Roles Each role object includes a `role` value and, when required, role-specific fields. | Field | Type | Description | | --------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `role` | string | Role the participant holds in this incorporation. Supported values are `DIRECTOR` and `SHAREHOLDER`. | | `ownershipPercentage` | number | Required when the participant has a shareholder role and ownership is represented by percentage. Participant writes are rejected if shareholder ownership would exceed the selected requirements total. | One participant can hold multiple roles when the same reusable resource satisfies multiple incorporation requirements. ## Documents The `documents` array contains participant document links created or replaced through [Upsert a participant document](/engine/incorporation/partner-incorporation-participant-documents-PUT). | Attribute | Type | Description | | --------------- | ------- | -------------------------------------------------------------------------------------------------------- | | `documentId` | string | Identifier for the participant document link. | | `participantId` | string | Participant this document belongs to. | | `documentKind` | string | Type of document linked to the participant. Supported values include `PASSPORT_SCAN` and `UTILITY_BILL`. | | `fileId` | integer | Commenda file satisfying this document requirement. | | `status` | string | Current status of the participant document link. Current value is `SUBMITTED`. | ## Endpoints | Action | Endpoint | | ------------------------ | --------------------------------------------------------------------------------------------------------- | | Register | [Register an incorporation participant](/engine/incorporation/partner-incorporation-participants-POST) | | List | [List incorporation participants](/engine/incorporation/partner-incorporation-participants-GET) | | Update roles or resource | [Update an incorporation participant](/engine/incorporation/partner-incorporation-participants-id-PATCH) | | Remove | [Remove an incorporation participant](/engine/incorporation/partner-incorporation-participants-id-DELETE) | | Upsert document | [Upsert a participant document](/engine/incorporation/partner-incorporation-participant-documents-PUT) | # List incorporation participants Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-participants-GET GET /partner/incorporation/{incorporationId}/participants List reusable Commenda OS people or business entities registered as participants in this incorporation, including their roles and linked documents. Lists participants registered to an incorporation. Use this endpoint to inspect the reusable Commenda OS resources attached to the incorporation, their director/shareholder roles, and any participant documents. The same participant can hold multiple roles. For example, one individual can be both a director and a 100% shareholder. # Register an incorporation participant Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-participants-POST POST /partner/incorporation/{incorporationId}/participants Register an existing Commenda OS person or business entity as a participant in an incorporation, including details about their role. Registers a reusable Commenda OS person or business entity as a participant in an incorporation. Participants are the incorporation-specific layer that assigns roles such as `DIRECTOR` and `SHAREHOLDER`. The underlying person or business entity remains reusable across Commenda OS for customer records, documents, registrations, and other entity-management work. The `resource.resourceId` value is the numeric Commenda OS person or business entity id. ```json theme={null} { "participantType": "INDIVIDUAL", "resource": { "resourceType": "KEY_PERSON", "resourceId": 12 }, "roles": [ { "role": "DIRECTOR" }, { "role": "SHAREHOLDER", "ownershipPercentage": 100 } ] } ``` The response returns the registered participant and the refreshed `incorporationValidation` for the incorporation. Registering a participant does not by itself make the underlying Commenda OS resource complete. The incorporation validation also checks required fields on the referenced person or business entity, such as legal names, email, nationality, date of birth, address, and corporate registration data when those fields are required by the selected jurisdiction. ## Role and resource matrix For Singapore private limited companies, use this matrix when mapping the requirements response into participant registration calls: | Participant scenario | `participantType` | `resource.resourceType` | Supported role payload | Ownership | Documents | | ---------------------------------------- | ----------------- | ----------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | | Individual director | `INDIVIDUAL` | `KEY_PERSON` | `{ "role": "DIRECTOR" }` | Not applicable | `PASSPORT_SCAN` and `UTILITY_BILL` when required. | | Individual shareholder | `INDIVIDUAL` | `KEY_PERSON` | `{ "role": "SHAREHOLDER", "ownershipPercentage": number }` | Required for percentage ownership. All shareholders must total 100. | `PASSPORT_SCAN` and `UTILITY_BILL` when required. | | Same individual director and shareholder | `INDIVIDUAL` | `KEY_PERSON` | Include both role objects in one `roles` array. | Shareholder role still needs `ownershipPercentage`. | One participant record can satisfy both role document requirements once its required documents are upserted. | | Corporate shareholder | `CORPORATE` | `BUSINESS_ENTITY` | `{ "role": "SHAREHOLDER", "ownershipPercentage": number }` | Required for percentage ownership. All shareholders must total 100. | Follow `documentRequirements` for `participantType: "CORPORATE"` and `resourceType: "BUSINESS_ENTITY"` when present. | | Corporate director | `CORPORATE` | `BUSINESS_ENTITY` | Not supported for Singapore private limited companies. | Not applicable | Not applicable. | Create individual resources with `POST /partner/commenda-os/customers/{customerId}/persons`. Create corporate resources with `POST /partner/commenda-os/customers/{customerId}/business-entities`. For Singapore private limited companies, writes that would make shareholder ownership exceed 100 are rejected. Ownership below 100 is accepted while the customer is still entering shareholders, but incorporation validation remains incomplete until the total equals 100. Use `PATCH /partner/incorporation/{incorporationId}/participants/{participantId}` to replace an existing participant's roles or correct ownership percentages. ## Role examples Director only: ```json theme={null} { "participantType": "INDIVIDUAL", "resource": { "resourceType": "KEY_PERSON", "resourceId": 12 }, "roles": [ { "role": "DIRECTOR" } ] } ``` Shareholder only: ```json theme={null} { "participantType": "INDIVIDUAL", "resource": { "resourceType": "KEY_PERSON", "resourceId": 13 }, "roles": [ { "role": "SHAREHOLDER", "ownershipPercentage": 40 } ] } ``` Corporate shareholder: ```json theme={null} { "participantType": "CORPORATE", "resource": { "resourceType": "BUSINESS_ENTITY", "resourceId": 44 }, "roles": [ { "role": "SHAREHOLDER", "ownershipPercentage": 60 } ] } ``` # Remove an incorporation participant Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-participants-id-DELETE DELETE /partner/incorporation/{incorporationId}/participants/{participantId} Remove an incorporation-specific participant registration and its linked participant documents. This does not delete the underlying Commenda OS person or business entity referenced by the participant. Removes a participant registration from an incorporation. This removes the incorporation-specific participant record and its linked participant documents. It does not delete the underlying Commenda OS person or business entity referenced by the participant, so that reusable resource can still be used elsewhere. The response returns the removed `participantId` and the refreshed `incorporationValidation` for the incorporation. # Update an incorporation participant Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-participants-id-PATCH PATCH /partner/incorporation/{incorporationId}/participants/{participantId} Partially update an existing incorporation participant. Use this endpoint to correct director/shareholder roles, shareholder ownership percentages, or to re-point the participant at a different Commenda OS person or business entity. Provide `roles`, `resource`, or both. The underlying Commenda OS resource is not modified by this endpoint. Partially updates an existing incorporation participant. Use this endpoint when a customer needs to correct director/shareholder roles, shareholder ownership percentages, or to re-point a participant at a different Commenda OS person or business entity after the participant has already been registered. The underlying Commenda OS resource is not modified by this endpoint. ## Request body Provide `roles`, `resource`, or both. At least one of the two fields is required. | Field | Type | Description | | ---------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `roles` | array | Optional. Full replacement set of roles for the participant. When provided, the supplied array fully replaces the existing roles and any omitted roles are removed. | | `resource` | object | Optional. Reusable Commenda OS resource the participant should reference. Provide `resource.resourceType` and `resource.resourceId` to re-point the participant at a different person or business entity. | ### Update roles only Send the full desired `roles` array. Omitted roles are removed. ```json theme={null} { "roles": [ { "role": "DIRECTOR" }, { "role": "SHAREHOLDER", "ownershipPercentage": 40 } ] } ``` ### Update the underlying resource only Re-point the participant at a different Commenda OS person or business entity while keeping the existing roles in place. ```json theme={null} { "resource": { "resourceType": "KEY_PERSON", "resourceId": 17 } } ``` The new resource must not already be registered as another participant on the same incorporation. Conflicts are rejected with a `400` response. The new resource must also be accessible to the partner; otherwise the request is rejected with a `403` response. ### Update both at once ```json theme={null} { "resource": { "resourceType": "KEY_PERSON", "resourceId": 17 }, "roles": [ { "role": "DIRECTOR" } ] } ``` ## Response The response returns the updated participant and the refreshed `incorporationValidation` for the incorporation. ```json theme={null} { "participant": { "id": "participant_123", "participantType": "INDIVIDUAL", "resource": { "resourceType": "KEY_PERSON", "resourceId": 12 }, "roles": [ { "role": "DIRECTOR" }, { "role": "SHAREHOLDER", "ownershipPercentage": 40 } ], "documents": [] }, "incorporationValidation": { "isComplete": false, "missingRequirements": [], "invalidRequirements": [ { "code": "SHAREHOLDER_OWNERSHIP_TOTAL_INVALID", "path": "participants.shareholders", "message": "Shareholders ownershipPercentage values must total 100" } ] } } ``` For Singapore private limited companies, shareholder ownership may not exceed 100 across registered shareholder participants. Updates below 100 are accepted, but incorporation validation remains incomplete until the shareholder total equals 100. # Get incorporation requirements Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-requirements-GET GET /partner/incorporation/requirements Retrieve the current requirements schema for a selected incorporation jurisdiction and type. This endpoint is informational; intake updates are validated against the current server-side incorporation requirements. Returns the current requirements for a selected incorporation. For Singapore private limited companies: ```bash theme={null} curl --request GET \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/requirements?country=SG&countryOptions[corporationType]=PRIVATE_LIMITED_COMPANY' \ --header 'x-api-key: ' ``` Use the returned requirements to render your intake UI and to understand required fields, participant roles, document requirements, and validation constraints. Rule of thumb: render from the requirements response, but validate from write/read responses. Intake updates are always validated against the current server-side requirements, so clients should handle `missingRequirements` and `invalidRequirements` from intake responses. For a renderer-oriented explanation of field kinds, input types, conditions, cardinality, constraints, and endpoint routing, see [Requirements guide](/engine/incorporation/partner-incorporation-requirements-guide). ## Participant role/resource combinations The requirements response describes participant requirements in terms of role, participant type, and resource type. For Singapore private limited companies: | Role requirement | `participantType` | `resource.resourceType` | Notes | | ---------------------- | ----------------- | ----------------------- | ------------------------------------------------------------------------- | | Individual director | `INDIVIDUAL` | `KEY_PERSON` | Use a Commenda OS person id. One person can also hold a shareholder role. | | Individual shareholder | `INDIVIDUAL` | `KEY_PERSON` | Use a Commenda OS person id and include `ownershipPercentage`. | | Corporate shareholder | `CORPORATE` | `BUSINESS_ENTITY` | Use a Commenda OS business entity id and include `ownershipPercentage`. | | Corporate director | `CORPORATE` | `BUSINESS_ENTITY` | Not supported for Singapore private limited companies. | When `documentRequirements` are returned, match them by `role`, `participantType`, and `resourceType`. Individual Singapore directors and shareholders require `PASSPORT_SCAN` and `UTILITY_BILL`; corporate shareholder documents, if required by the selected incorporation type, are surfaced by the same `documentRequirements` array. Some participant requirements also include `resourceFieldsByParticipantType`. These are fields on the Commenda OS resource you registered as the participant. For example, Singapore individual directors require the key person to have `residentialAddress`. Satisfy that field by creating or updating the person with `residentialAddress`; it is not a reusable Commenda OS Location and should not be sent as `registeredOfficeAddressLocation`. Requirements snippet: ```json theme={null} { "participantRequirements": [ { "key": "directors", "role": "DIRECTOR", "allowedParticipantTypes": ["INDIVIDUAL"], "allowedResourceTypes": ["KEY_PERSON"], "resourceFieldsByParticipantType": { "INDIVIDUAL": [ { "kind": "resource", "key": "residentialAddress", "required": true, "commendaOs": { "entity": "keyPerson", "field": "residentialAddress" } } ] } } ] } ``` If validation later returns: ```json theme={null} { "path": "participants.participant_123.resource.residentialAddress", "message": "Residential address is required" } ``` Find `participant_123` in the incorporation response: ```json theme={null} { "id": "participant_123", "resource": { "resourceType": "KEY_PERSON", "resourceId": 12 } } ``` Then update person `12`: ```json theme={null} { "residentialAddress": { "addressLine1": "1 Raffles Place", "city": "Singapore", "postalCode": "048616", "country": "SG" } } ``` Validation paths in `missingRequirements` and `invalidRequirements` correspond to requirements fields or participant/document requirements. Field validation paths include the requirements block key, such as `companyNames.companyNameOptions`, even though the intake payload key remains `requirements.companyNameOptions`. Participant resource paths look like `participants.participant_123.resource.residentialAddress`. Participant document paths look like `participants.participant_123.documents.PASSPORT_SCAN`. You may cache the requirements response by `country` plus `countryOptions`, but do not send a requirements version back to Commenda. If validation returns new missing or invalid requirements, update your UI from the latest response. # Requirements guide Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-requirements-guide Render incorporation requirements and submit the resulting values to the right Partner API endpoints. The requirements response is the form contract for one incorporation type. Use it to decide which fields to render, which participant roles to collect, which Commenda OS records must be completed, and which document uploads are required. Do not send the requirements response back unchanged. Render from requirements, save values through the endpoint family that owns each requirement, and use `incorporationValidation` to decide whether the incorporation is ready to submit. | Question | Where to look | What your integration should do | | ------------------------------------------------------------------ | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | | What incorporation-level fields do I ask for? | `blocks[].fields` | Render these fields and submit values through `PATCH /partner/incorporation/{incorporationId}/intake` under `requirements`. | | Who must be attached to the incorporation? | `participantRequirements` | Create or reuse Commenda OS people/business entities, then register them as participants. | | What data must exist on a participant's person or business entity? | `resourceFieldsByParticipantType` | Render these fields on the participant form and submit them through the relevant Commenda OS Partner API endpoint. | | What files must be attached to a participant? | `documentRequirements` | Upload a customer file, then upsert it into the participant's required document slot. | | Why is validation still incomplete? | `missingRequirements` and `invalidRequirements` | Follow each validation path back to the field, participant, resource field, or document slot that needs attention. | If one participant has multiple roles with the same required `documentKind`, one upsert for that participant and `documentKind` satisfies the overlapping requirement. ## Renderer model Build your renderer around each field's `kind`. | `kind` | Render as | Value shape | Submit through | | ------------ | ------------------------------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- | | `scalar` | One input control using `input.type` | Primitive string, number, or boolean | Parent destination. For `blocks[].fields`, send under `requirements.{key}`. | | `object` | A nested group of fields | Object keyed by child field keys | Parent destination. Object fields can appear anywhere a field is accepted; the current Singapore requirements use them as collection items. | | `collection` | Repeating items | Array of item objects or resource objects | Parent destination. Use `cardinality` and `constraints` to size and validate the list. | | `resource` | A resource picker or nested resource fields | Depends on location in the requirements response | For intake blocks, send a resource object. For participant resource fields, update the referenced Commenda OS resource. | For `blocks[].fields`, field keys become top-level keys in the intake `requirements` object. For nested `object` and `collection` fields, preserve the nested shape under the parent key. Use each field's `key` to build request payloads. `commendaOs.field` is an absolute Commenda OS mapping path, not the nested JSON key for the current renderer position. For `participantRequirements[].resourceFieldsByParticipantType`, field keys describe data that must exist on the registered participant's `resource`. Do not send those values to the intake endpoint. Update the referenced person or business entity through the Commenda OS Partner API. The intake endpoint rejects unknown keys with `400 Bad Request`. Sending participant-shaped values such as `participants`, `directors`, top-level `residentialAddress`, or a nested `resource` object under `requirements` fails validation before any state is stored. See [Update incorporation intake](/engine/incorporation/partner-incorporation-intake-PATCH) for the full list of routing rules. ## Scalar input types `input.type` is the UI hint for scalar fields. | `input.type` | Suggested control | Submit value | | ------------------------------------------------------- | ----------------------------------------------- | --------------------------- | | `text`, `textarea`, `email`, `phone`, `date`, `country` | Text-like input, date picker, or country picker | String | | `select` | Select, radio group, or segmented control | The selected option `value` | | `number`, `percent` | Numeric input | Number | For `select`, render from `input.options`. Treat option `value` as the exact API value and option `name`/`description` as display copy. The API validates option values as sent; do not normalize, uppercase, or otherwise change casing. Use `input.placeholder` and `input.examples` as hints only. They are not defaults. ## Required and applicable fields `required` and `appliesWhen` are separate concepts. | Property | Meaning | Renderer behavior | Validation behavior | | ----------------- | ------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | | `required: true` | The field is always required when applicable. | Mark required. | Missing value blocks submit. | | `required: false` | The field is optional. | Mark optional. | Missing value does not block submit. | | `required.when` | The field is conditionally required. | Recompute required state when the controlling field changes. | Missing value blocks submit only when the condition matches. | | `appliesWhen` | The field only applies for a selected condition. | Hide or disable the field when the condition does not match. | Non-applicable fields are ignored by validation. | Because intake updates are merge-based, `currentState` is the merged history of accepted intake patches. It can contain values that are stale or no longer applicable after later choices. Treat `incorporationValidation` as the source of truth for readiness, not the presence of keys in `currentState`. ## Cardinality and constraints Collections and participant requirements can define `cardinality`. | Property | Meaning | Example renderer behavior | | ------------------- | ----------------------------------------------- | ------------------------------------- | | `cardinality.exact` | The list must contain exactly this many items. | Render a fixed number of rows. | | `cardinality.min` | The list must contain at least this many items. | Render one row and allow adding more. | | `cardinality.max` | The list must contain at most this many items. | Disable add after the maximum. | Collections can also define `constraints`. | Constraint | Meaning | Example renderer behavior | | ------------- | ------------------------------------------------------------- | ------------------------------------------------------------- | | `uniqueItems` | Items must be unique by the listed fields. | Warn before submit when two rows share the same field values. | | `sumEquals` | Numeric values across all items must total a specific number. | Show a running total and block submit when the total is off. | Scalar fields can define `validation`, such as `minLength`, `maxLength`, `min`, `max`, or `pattern`. Use these to provide inline validation, but still handle server-side `invalidRequirements`. ## Resource fields Resource fields have different submission shapes depending on where they appear. ### Intake resource fields When a resource field appears under `blocks[].fields`, submit a resource object through the intake endpoint. | Resource object field | Required | Description | | --------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | | `mode` | Yes | Must be `existingResource` or `inlineData`. | | `resourceId` | When `mode` is `existingResource` | ID of an accessible Commenda OS resource of the type named by `commendaOsResource.entity`. | | `data` | When `mode` is `inlineData`; optional for `existingResource` | Field values for this resource requirement. | When a resource field includes a `fields` array, those child fields describe the keys accepted under `data`. For `existingResource`, `data` supplements the saved resource values for incorporation validation. For `inlineData`, `data` is the full submitted resource value. Use child field `key` values as the `data` keys. Child `commendaOs.field` values, when present, are absolute paths from the Commenda OS resource root. Use `existingResource` when the customer already has a Commenda OS resource: ```json theme={null} { "requirements": { "registeredOfficeAddressSource": "partnerProvidedLocation", "registeredOfficeAddressLocation": { "mode": "existingResource", "resourceId": "location_001" } } } ``` You can include `data` when the existing resource is missing supplemental fields required for this incorporation: ```json theme={null} { "requirements": { "registeredOfficeAddressSource": "partnerProvidedLocation", "registeredOfficeAddressLocation": { "mode": "existingResource", "resourceId": "location_001", "data": { "addressLine1": "1 Raffles Place", "postalCode": "048616", "country": "SG" } } } } ``` Use `inlineData` when the incorporation should store the resource data only for this intake value: ```json theme={null} { "requirements": { "registeredOfficeAddressSource": "partnerProvidedLocation", "registeredOfficeAddressLocation": { "mode": "inlineData", "data": { "addressLine1": "1 Raffles Place", "postalCode": "048616", "country": "SG" } } } } ``` `commendaOs.field` tells you where a field maps on a Commenda OS resource. `commendaOsResource.entity` tells you what kind of Commenda OS resource an `existingResource` value should reference. It does not create the resource automatically. ### Participant resource fields When a resource field appears under `participantRequirements[].resourceFieldsByParticipantType`, it describes data that must exist on the registered participant's Commenda OS resource. Do not render the intake resource object controls (`mode` and `resourceId`) for participant resource fields. Render the nested fields and submit them to the referenced person or business entity endpoint. For Singapore individual directors and shareholders, `residentialAddress` is a required resource field on the `KEY_PERSON` resource. Satisfy it by updating the referenced person: ```json theme={null} { "residentialAddress": { "addressLine1": "1 Raffles Place", "city": "Singapore", "postalCode": "048616", "country": "SG" } } ``` This is not an intake value and it is not the registered office address location. Submit it through `POST /partner/commenda-os/customers/{customerId}/persons` or `PATCH /partner/commenda-os/customers/{customerId}/persons/{personId}`. The Partner API person endpoints accept `residentialAddress` directly. They do not accept a person `locations` array. If a child field under `residentialAddress` has `key: "addressLine1"` and `commendaOs.field: "residentialAddress.addressLine1"`, submit it once under the parent object: `{ "residentialAddress": { "addressLine1": "1 Raffles Place" } }`. Do not submit `{ "residentialAddress": { "residentialAddress": { "addressLine1": "1 Raffles Place" } } }`. ## Worked example: Singapore Pte. Ltd. This requirements snippet says to collect exactly three unique company names: ```json theme={null} { "key": "companyNames", "fields": [ { "kind": "collection", "key": "companyNameOptions", "name": "Company name options", "cardinality": { "exact": 3 }, "constraints": [{ "kind": "uniqueItems", "fields": ["name"] }], "item": { "kind": "object", "fields": [ { "kind": "scalar", "key": "name", "name": "Proposed company name", "input": { "type": "text" }, "validation": { "minLength": 1, "maxLength": 120 } } ] } } ] } ``` A renderer should show three text inputs, validate each `name`, and prevent duplicate names before submit. Submit the values through intake: ```json theme={null} { "requirements": { "companyNameOptions": [ { "name": "Acme SG Pte Ltd" }, { "name": "Acme Asia Pte Ltd" }, { "name": "Acme Global Pte Ltd" } ] } } ``` This requirements snippet says to render a select for registered office address source. The location field is only visible and required when the user chooses `partnerProvidedLocation`: ```json theme={null} { "key": "registeredOfficeAddress", "fields": [ { "kind": "scalar", "key": "registeredOfficeAddressSource", "name": "Registered office address source", "required": true, "input": { "type": "select", "options": [ { "value": "commendaService", "name": "Use Commenda service" }, { "value": "partnerProvidedLocation", "name": "Use partner-provided location" } ] } }, { "kind": "resource", "key": "registeredOfficeAddressLocation", "required": { "when": { "fieldKey": "registeredOfficeAddressSource", "equals": "partnerProvidedLocation" } }, "appliesWhen": { "fieldKey": "registeredOfficeAddressSource", "equals": "partnerProvidedLocation" }, "commendaOsResource": { "entity": "location" }, "fields": [ { "kind": "scalar", "key": "addressLine1", "input": { "type": "text" } }, { "kind": "scalar", "key": "city", "input": { "type": "text" } }, { "kind": "scalar", "key": "postalCode", "input": { "type": "text" } }, { "kind": "scalar", "key": "country", "input": { "type": "country" } } ] } ] } ``` If the user chooses Commenda's registered office service, submit only the selected option: ```json theme={null} { "requirements": { "registeredOfficeAddressSource": "commendaService" } } ``` If the user chooses a partner-provided location, submit the selected source plus the resource object: ```json theme={null} { "requirements": { "registeredOfficeAddressSource": "partnerProvidedLocation", "registeredOfficeAddressLocation": { "mode": "existingResource", "resourceId": "location_001" } } } ``` If the user chooses `inlineData` for that location field, use the same child `fields` keys under `data`: ```json theme={null} { "requirements": { "registeredOfficeAddressSource": "partnerProvidedLocation", "registeredOfficeAddressLocation": { "mode": "inlineData", "data": { "addressLine1": "1 Raffles Place", "city": "Singapore", "postalCode": "048616", "country": "SG" } } } } ``` Participant requirements are rendered separately from intake fields. For an individual director, create or update a person, register that person as a participant, and attach required documents: ```json theme={null} { "participantType": "INDIVIDUAL", "resource": { "resourceType": "KEY_PERSON", "resourceId": 12 }, "roles": [{ "role": "DIRECTOR" }] } ``` If validation returns: ```json theme={null} { "path": "participants.participant_123.resource.residentialAddress", "message": "Residential address is required" } ``` Find `participant_123` in the incorporation response, read `participant.resource.resourceId`, then update that person: ```json theme={null} { "residentialAddress": { "addressLine1": "1 Raffles Place", "city": "Singapore", "postalCode": "048616", "country": "SG" } } ``` ## Validation paths Validation paths in `missingRequirements` and `invalidRequirements` point to the missing or invalid item: | Example path | Meaning | Fix | | ---------------------------------------------------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | | `companyNames.companyNameOptions` | Company name options are missing or invalid | Submit valid names through the intake endpoint as `requirements.companyNameOptions`. | | `registeredOfficeAddress.registeredOfficeAddressLocation` | A partner-provided registered office address location is required | Submit `requirements.registeredOfficeAddressLocation` or choose `commendaService`. | | `participants.directors` | A required director participant is missing | Register a person or business entity as a director. | | `participants.participant_123.resource.residentialAddress` | A registered participant's referenced person is missing a residential address | Update that Commenda OS person with `residentialAddress`. | | `participants.participant_123.documents.PASSPORT_SCAN` | A participant is missing a passport scan | Upload a customer file, then upsert it as `PASSPORT_SCAN` for that participant. | Your renderer can prevent many invalid values before submit, but Commenda validation is authoritative. After every write, read `incorporationValidation`; the incorporation is ready to submit when `incorporationValidation.isComplete` is `true`. ## Renderer helpers Most renderers need only a small set of pure helpers: | Helper | Purpose | | --------------------------------------------- | --------------------------------------------------------------- | | `evalAppliesWhen(rule, values)` | Returns whether a field applies for the current sibling values. | | `evalRequired(required, values)` | Handles boolean `required` and `required.when`. | | `padToCardinality(items, cardinality)` | Initializes fixed or minimum collection rows. | | `findUniqueItemsViolation(items, constraint)` | Checks `uniqueItems` constraints before submit. | Keep client-side validation helpful but non-authoritative. The server may add or change requirements, and `incorporationValidation` remains the final contract for submit readiness. # Get incorporation status Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-status-GET GET /partner/incorporation/{incorporationId}/status Retrieve the current public status projection for an incorporation, including top-level status, ordered stages, and active blocking issue ids. Retrieves the current public status projection for an incorporation. Use this endpoint for progress views after an incorporation is created. It returns the top-level `incorporationStatus`, the workflow version used for the incorporation, ordered stages, and any active issues blocking the incorporation. ## Stage fields Each item in `stages` has these fields: | Field | Type | Meaning | | ------------------- | -------------- | ------------------------------------------------------------------------ | | `id` | string | Stable stage identifier. Use this as the React key for a stage row/card. | | `label` | string | Human-readable stage label. | | `description` | string | Human-readable explanation of the stage. | | `owner` | string | Party expected to own the work: `PARTNER`, `CUSTOMER`, or `COMMENDA`. | | `position` | integer | One-based display order. | | `status` | string | Current stage progress. | | `startedAt` | string or null | When work in this stage first started. | | `completedAt` | string or null | When this stage completed, or `null` if it is not complete. | | `blockedByIssueIds` | string\[] | Active issue ids blocking this stage. | ## Example ```bash theme={null} curl --request GET \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/0f9a8f5e-7f7c-4c1b-a60a-b1022f9d8c91/status' \ --header 'x-api-key: ' ``` ```json theme={null} { "incorporationStatus": "BLOCKED", "incorporationId": "0f9a8f5e-7f7c-4c1b-a60a-b1022f9d8c91", "customerId": 77, "country": "SG", "countryOptions": { "corporationType": "PRIVATE_LIMITED_COMPANY" }, "statusWorkflow": { "schemaVersion": "2026-04-26", "definitionVersion": "1.0.0", "key": "singapore-incorporation-partner-api" }, "blockingIssueIds": ["issue_123"], "blockingIssueCount": 1, "stages": [ { "id": "intake", "label": "Intake", "description": "Collect required incorporation information and documents.", "owner": "PARTNER", "position": 1, "status": "COMPLETED", "startedAt": "2026-04-26T18:10:00.000Z", "completedAt": "2026-04-26T18:30:00.000Z", "blockedByIssueIds": [] }, { "id": "kyc", "label": "KYC", "description": "Review required identity, ownership, and compliance materials.", "owner": "COMMENDA", "position": 2, "status": "BLOCKED", "startedAt": "2026-04-26T19:05:00.000Z", "completedAt": null, "blockedByIssueIds": ["issue_123"] } ], "updatedAt": "2026-04-26T19:15:00.000Z" } ``` ## Top-level status | Status | Meaning | | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `AWAITING_CUSTOMER_INPUT` | Required intake information, participant roles, or documents are missing or invalid, or the complete intake has not been submitted yet. | | `SUBMITTED` | The incorporation was submitted and still validates, but Commenda review has not started yet. | | `IN_PROGRESS` | Commenda review is in progress. | | `BLOCKED` | The incorporation has active partner-visible issues or review start/runtime failures. | | `COMPLETED` | The incorporation is complete. | ## Stage status | Status | Meaning | | ------------- | ------------------------------------------------------------------------- | | `NOT_STARTED` | The stage has not started. | | `IN_PROGRESS` | At least one task in the stage has started and the stage is not complete. | | `BLOCKED` | The stage is blocked by active issue ids or failed review work. | | `COMPLETED` | The stage is complete. | Active issues are listed in `blockingIssueIds`. If an issue has a `scope.stageId`, that issue appears on the matching stage's `blockedByIssueIds`; otherwise it blocks the first non-completed stage. # Get status workflow Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-status-workflow-GET GET /partner/incorporation/status-workflow Retrieve the public status workflow for a selected incorporation jurisdiction and type. The response is derived from the active workflow template and includes ordered public stages. Retrieves the public status workflow for a selected incorporation jurisdiction and type. Use this endpoint after the customer chooses `country` and `countryOptions` if you want to render a progress UI before the incorporation is created. The workflow is informational and versioned. Incorporation progress is returned by [Get incorporation status](/engine/incorporation/partner-incorporation-status-GET). ## Query shape Use the same deep-object query syntax as the requirements endpoint. ```bash theme={null} curl --request GET \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/status-workflow?country=SG&countryOptions[corporationType]=PRIVATE_LIMITED_COMPANY' \ --header 'x-api-key: ' ``` ## Response ```json theme={null} { "statusWorkflow": { "schemaVersion": "2026-04-26", "definitionVersion": "1.0.0", "key": "singapore-incorporation-partner-api", "country": "SG", "countryOptions": { "corporationType": "PRIVATE_LIMITED_COMPANY" }, "name": "Singapore Private Limited Company Incorporation", "description": "Track the public progress of a Singapore private limited company incorporation.", "stages": [ { "id": "intake", "label": "Intake", "description": "Collect required incorporation information and documents.", "owner": "PARTNER", "position": 1 }, { "id": "kyc", "label": "KYC", "description": "Review required identity, ownership, and compliance materials.", "owner": "COMMENDA", "position": 2 } ] } } ``` ## Stage owners | Owner | Meaning | | ---------- | ------------------------------------------------------- | | `PARTNER` | The partner integration or partner team owns the stage. | | `CUSTOMER` | The end customer must provide input. | | `COMMENDA` | Commenda owns the stage. | If the status workflow is not active for the selected incorporation type, the endpoint returns `404`. # Submit an incorporation Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-submit-POST POST /partner/incorporation/{incorporationId}/submit Submit a currently complete incorporation for Commenda review. The server refreshes validation before accepting the submit request. `incorporationValidation.isComplete` means eligible to submit; `SUBMITTED` or `IN_PROGRESS` is returned only after this endpoint succeeds. Submits a complete incorporation and begins Commenda review. Use this endpoint after the current incorporation state satisfies the incorporation requirements. `incorporationValidation.isComplete` means the incorporation is eligible to submit; it does not move to `SUBMITTED` or `IN_PROGRESS` until you call this endpoint. This endpoint refreshes validation before accepting the submit request. If required intake fields, participants, ownership totals, or participant documents are still missing or invalid, the request returns `400` and the response includes validation details. Submit is idempotent for an already-submitted, still-complete incorporation. Retrying submit returns the current incorporation resource instead of starting a second review. ## Incomplete submit response ```json theme={null} { "statusCode": 400, "message": "Incorporation intake is incomplete and cannot be submitted for review", "error": "Bad Request", "incorporationValidation": { "isComplete": false, "missingRequirements": [ { "code": "PARTICIPANT_REQUIRED", "path": "participants.directors", "message": "At least one director is required" } ], "invalidRequirements": [] } } ``` ## Lifecycle effect ```text theme={null} AWAITING_CUSTOMER_INPUT -> SUBMITTED after POST /submit succeeds and before Commenda review work starts -> IN_PROGRESS when Commenda review is in progress -> BLOCKED when there are active partner-visible issues or review start/runtime failures -> COMPLETED when the incorporation is complete ``` # Get incorporation validation Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-validation-GET GET /partner/incorporation/{incorporationId}/validation Refresh and retrieve validation for the full incorporation, including intake fields, participants, ownership totals, and participant documents. Refreshes and returns validation for the full incorporation. Use this endpoint when your UI needs the latest readiness state without fetching the full incorporation resource. The response includes `incorporationValidation` only. # Incorporation validation object Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-validation-object Field reference for incorporation readiness and validation issues. The `incorporationValidation` object represents validation for the full incorporation: incorporation-level intake fields, participants, ownership totals, participant resources, and participant documents. Use `incorporationValidation` to decide whether the incorporation is ready to submit. It is returned by incorporation read/write endpoints and can be refreshed directly with [Get incorporation validation](/engine/incorporation/partner-incorporation-validation-GET). ## Attributes | Attribute | Type | Description | | --------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `isComplete` | boolean | `true` when the current incorporation state satisfies the current requirements and is eligible to submit for review. This does not submit the incorporation by itself. | | `missingRequirements` | array | Required fields, participants, ownership totals, participant resource fields, or participant documents that have not been provided yet. | | `invalidRequirements` | array | Submitted values that do not satisfy the current requirements. | When `incorporationValidation.isComplete` is `true`, call [Submit an incorporation](/engine/incorporation/partner-incorporation-submit-POST) to hand the incorporation to Commenda for review. ## Validation issues Each item in `missingRequirements` and `invalidRequirements` has the same shape. | Attribute | Type | Description | | --------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `code` | string | Stable machine-readable validation issue code. | | `path` | string | Dot/bracket path for the missing or invalid requirement. Values depend on the current requirements and participant ids, such as `companyNames.companyNameOptions` or `participants.participant_123.documents.PASSPORT_SCAN`. | | `message` | string | Human-readable explanation of what is missing or invalid. | | `participantId` | string | Present when the issue belongs to a participant. | | `documentKind` | string | Present when the issue belongs to a participant document. | | `displayName` | string | Present when Commenda can provide a useful label for the affected person, business entity, or field. | ## Endpoints | Action | Endpoint | | -------------------------------------- | -------------------------------------------------------------------------------------------------------- | | Read current validation | [Get incorporation validation](/engine/incorporation/partner-incorporation-validation-GET) | | Update intake and validate | [Update incorporation intake](/engine/incorporation/partner-incorporation-intake-PATCH) | | Register participant and validate | [Register an incorporation participant](/engine/incorporation/partner-incorporation-participants-POST) | | Update participant and validate | [Update an incorporation participant](/engine/incorporation/partner-incorporation-participants-id-PATCH) | | Upsert document and validate | [Upsert a participant document](/engine/incorporation/partner-incorporation-participant-documents-PUT) | | Retrieve incorporation with validation | [Get an incorporation](/engine/incorporation/partner-incorporation-incorporations-id-GET) | # Incorporation webhooks Source: https://docs.commenda.io/engine/incorporation/partner-incorporation-webhooks Receive partner incorporation issue events. Partner incorporation webhooks notify your integration when Commenda creates or resolves a partner-visible incorporation issue. Supported incorporation event types: | Event type | Trigger | | ------------------------------ | -------------------------------------------------------------- | | `INCORPORATION_ISSUE_CREATED` | Commenda creates a partner-visible issue for an incorporation. | | `INCORPORATION_ISSUE_RESOLVED` | Commenda resolves a partner-visible issue. | Use [List incorporation issues](/engine/incorporation/partner-incorporation-issues-GET) to fetch the current issue state directly. Use the top-level [Partner webhooks](/engine/partner-webhooks/partner-webhooks) docs for subscription management, delivery behavior, signatures, payload shape, retries, and event idempotency. ## Subscribe Create a partner-level webhook subscription with the issue events you want to receive: ```bash theme={null} curl --request POST \ --url 'https://api.prod.commenda.io/api/v1/partner/webhook-subscriptions' \ --header 'content-type: application/json' \ --header 'x-api-key: ' \ --data '{ "url": "https://partner.example.com/commenda/webhooks", "eventTypes": [ "INCORPORATION_ISSUE_CREATED", "INCORPORATION_ISSUE_RESOLVED" ] }' ``` The subscription is partner-level, not scoped to one company or incorporation. ## Correction cycle semantics Each issue row represents one remediation episode. Resolved incorporation issues are not reopened; if the same kind of correction is needed again later, Commenda creates a new issue and emits a new `INCORPORATION_ISSUE_CREATED` event. # List payment intents Source: https://docs.commenda.io/engine/incorporation/payment-intents-GET GET /public/payment-intents List payment intents visible to the authenticated affiliate, optionally filtered by status or company. Lists payment intents visible to the authenticated affiliate. Use the optional filters to narrow to a single company or payment state. When you pass a `companyId` filter, the API verifies that the company belongs to the authenticated affiliate. Requests that reference a company outside the affiliate's scope return `403 Forbidden`. # Get a payment intent Source: https://docs.commenda.io/engine/incorporation/payment-intents-id-GET GET /public/payment-intents/{paymentIntentId} Retrieve a single payment intent and its linked service request handoff URL. Returns the payment intent id plus the linked `serviceRequestURL` in the app when the service request already exists. # Get payment intent service status Source: https://docs.commenda.io/engine/incorporation/payment-intents-id-service-status-GET GET /public/payment-intents/{paymentIntentId}/service/status Retrieve the linked service request summary and task-group level status for a payment intent. Returns the linked service request summary and the current task-group level progress for the underlying incorporation workflow. # Create an incorporation service Source: https://docs.commenda.io/engine/incorporation/services-POST POST /public/services Start a supported incorporation service for an affiliate-owned company and return the linked payment intent id. Creates a supported incorporation service for an affiliate-owned company and returns the `paymentIntentId` used by the current public handoff flow. ## Supported service types Only the following `serviceType` values are accepted: | Service type | Description | | ----------------------------- | --------------------------- | | `US_CCORP_INCORPORATION` | United States C-Corporation | | `US_LLC_INCORPORATION` | United States LLC | | `CA_CORP_INCORPORATION` | Canada Corporation | | `INDIA_PVT_LTD_INCORPORATION` | India Private Limited | | `INDIA_LLP_INCORPORATION` | India LLP | | `UAE_INCORPORATION` | United Arab Emirates | | `UK_INCORPORATION` | United Kingdom | | `IE_INCORPORATION` | Ireland | | `SG_INCORPORATION` | Singapore | Requests with an unsupported `serviceType` return `400 Bad Request` with a message listing the valid options. ```json Example error response theme={null} { "statusCode": 400, "message": [ "serviceType must be one of the supported legacy affiliate API services: US_CCORP_INCORPORATION, US_LLC_INCORPORATION, CA_CORP_INCORPORATION, INDIA_PVT_LTD_INCORPORATION, INDIA_LLP_INCORPORATION, UAE_INCORPORATION, UK_INCORPORATION, IE_INCORPORATION, SG_INCORPORATION" ], "error": "Bad Request" } ``` # Address requirements Source: https://docs.commenda.io/engine/indirect-tax/address-requirements/address-requirements Look up which address fields are required, optional, or ignored for each country. ## Overview Different countries have different address formats and requirements. The address requirements endpoint lets you look up the minimum address fields needed for a given country before submitting addresses for tax calculations or transactions. Use this endpoint to: * **Validate addresses client-side** before calling `/calculate` or `/transactions`, reducing failed requests. * **Build dynamic address forms** that adapt to each country's requirements. * **Check postal code formats** using the provided regex pattern. * **Restrict state/province inputs** to valid codes for the country. ## Field requirement levels Each address field returns one of three requirement levels: | Level | Meaning | | ---------- | ------------------------------------------------------------------------- | | `REQUIRED` | The field must be provided. Omitting it may cause tax calculation errors. | | `OPTIONAL` | The field is accepted but not mandatory. Providing it improves accuracy. | | `IGNORED` | The field is not used for this country and can be omitted. | ## How address requirements are used The `/calculate` and `/transactions` endpoints only require `country` at the schema level for all addresses. All other field requirements — including `postal_code` and `state` — are determined per-country using the rules returned by this endpoint. If a field marked as `REQUIRED` for a country is missing or incorrectly formatted, the API returns a `400` error with details about the validation failure. Querying address requirements ahead of time lets you catch these issues before submitting a request. ## Regional differences Address requirements vary by country and region. Here are some key differences to be aware of: * **United States (US):** `address_line_1`, `city`, `state`, and `postal_code` are all `REQUIRED`. State codes must be valid 2-letter US state abbreviations (e.g., `CA`, `NY`). * **EU countries (e.g., DE, FR):** `address_line_1`, `city`, and `postal_code` are `REQUIRED`, while `state` is `OPTIONAL`. Postal codes are validated against the country's regex pattern. * **United Kingdom (GB):** `address_line_1`, `city`, and `postal_code` are `REQUIRED`, while `state` is `OPTIONAL`. Postal codes must match the UK format (e.g., `SW1A 1AA`). * **Canada (CA):** `address_line_1` and `city` are `REQUIRED`. `state` and `postal_code` requirements follow Canadian postal standards. When provided, state codes must be valid 2-letter province/territory abbreviations (e.g., `ON`, `BC`). Even when a field is `OPTIONAL`, providing it improves tax calculation accuracy. For example, including a state code for EU or GB addresses helps resolve the correct tax jurisdiction. ## Postal code validation When `postal_code_regex` is present in the response, you can use it to validate postal codes before submission. For example, the US pattern `^\d{5}(-\d{4})?$` accepts both 5-digit and 9-digit ZIP codes. The `postal_code` field is **required** for the US, EU countries (such as DE and FR), and GB. For CA, `postal_code` is optional. When a postal code is provided, it is validated against the country's regex pattern. ## Valid state codes For countries with defined state or province subdivisions (e.g., US, CA), the `valid_state_codes` array lists all accepted codes. Use this to populate dropdowns or validate state input in your address forms. # Get address requirements Source: https://docs.commenda.io/engine/indirect-tax/address-requirements/address-requirements-GET GET /address-requirements Returns the minimum address field requirements for a given country. Use this to determine which address fields are required, optional, or ignored when submitting addresses for tax calculations and transactions. ```bash US theme={null} curl -X GET "https://transaction-tax.api.in.commenda.io/api/v1/address-requirements?country=US" \ -H "Authorization: Bearer " ``` ```bash GB theme={null} curl -X GET "https://transaction-tax.api.in.commenda.io/api/v1/address-requirements?country=GB" \ -H "Authorization: Bearer " ``` ```bash DE theme={null} curl -X GET "https://transaction-tax.api.in.commenda.io/api/v1/address-requirements?country=DE" \ -H "Authorization: Bearer " ``` ```json US (200) theme={null} { "data": { "country_code": "US", "address_line_1": "REQUIRED", "address_line_2": "OPTIONAL", "address_line_3": "IGNORED", "city": "REQUIRED", "state": "REQUIRED", "postal_code": "REQUIRED", "postal_code_regex": "^\\d{5}(-\\d{4})?$", "valid_state_codes": [ "AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY", "DC" ] }, "message": "Successfully retrieved address requirements." } ``` ```json GB (200) theme={null} { "data": { "country_code": "GB", "address_line_1": "REQUIRED", "address_line_2": "OPTIONAL", "address_line_3": "IGNORED", "city": "REQUIRED", "state": "OPTIONAL", "postal_code": "REQUIRED", "postal_code_regex": "^[A-Za-z]{1,2}\\d[A-Za-z\\d]? ?\\d[A-Za-z]{2}$" }, "message": "Successfully retrieved address requirements." } ``` ```json DE (200) theme={null} { "data": { "country_code": "DE", "address_line_1": "REQUIRED", "address_line_2": "OPTIONAL", "address_line_3": "IGNORED", "city": "REQUIRED", "state": "OPTIONAL", "postal_code": "REQUIRED", "postal_code_regex": "^\\d{5}$" }, "message": "Successfully retrieved address requirements." } ``` ```json 400 theme={null} { "type": "INVALID_REQUEST_BODY", "title": "Invalid request body.", "detail": { "description": "country query parameter is required" }, "status": 400 } ``` ```json 404 theme={null} { "type": "RESOURCE_NOT_FOUND", "sub_type": "ADDRESS_REQUIREMENTS_NOT_FOUND", "title": "Address requirements not found.", "detail": { "description": "No address requirements found for country: HM" }, "status": 404 } ``` # Tax Calculations Source: https://docs.commenda.io/engine/indirect-tax/calculate/calculate Calculates the tax amount for a given transaction. ## Overview The `/calculate` endpoint allows you to determine the amount of indirect tax to charge on a transaction. By providing details such as customer information, line items, and pricing, you'll receive accurate tax calculations based on applicable jurisdictions and rates. ## Supported countries The calculation engine currently supports the following countries: | Country | Code | Ship-from address required | | -------------- | ---- | -------------------------- | | United States | `US` | No | | United Kingdom | `GB` | Yes | For UK (`GB`) calculations, you must include a `ship_from` address in your request. If omitted, the API returns a `400` error. ### Address validation When you submit a calculation request, the API validates your addresses against the destination country's requirements. Only `country` is required at the schema level for all addresses. Other fields such as `postal_code` and `state` are conditionally required depending on the destination country. For example, US addresses require both `postal_code` and `state`, while GB addresses require `postal_code` but treat `state` as optional. You can look up which fields are required for a given country using the [address requirements endpoint](/engine/indirect-tax/address-requirements/address-requirements-GET) before making a calculation request. ## Factors affecting tax rates Our system considers the following factors to determine the appropriate tax for a transaction: 1. **Seller Information** * **State Registrations**: * If your corporation is not registered to pay taxes in a state, the `/calculate` endpoint will return a tax amount of 0 for that state. * If your corporation is registered in a state, we calculate the tax amount based on that state’s rates and rules. 2. **Product-Specific Information** * **Product Taxability**: * **Product Configuration**: Each corporation can define and manage its product catalog via our `/products` endpoints. (Coming soon) * **Product Code Assignment**: For every product in the catalog, you can assign a specific product code using the API. * **Tax Rate Computation**: When the `/calculate` endpoint is called, each line item includes a product id. We use this id to retrieve the pre-configured product code for that product, determining its taxability for the transaction. * If a product is classified as non-taxable based on its product code, the tax amount for that specific line item will be 0. * If a product is taxable, the tax is calculated based on the product’s price and applicable tax rates. 3. **Customer Information** * **Shipping address**: We compute the tax rate based on the ship-to address provided for each transaction. * **Ship-from address**: For some countries (e.g., `GB`), the ship-from address is required and factors into the tax calculation. * **Customer exemptions**: Transactions can be exempted from sales tax based on properties of the customer making the purchase. You can read more about these exemptions [here](/engine/indirect-tax/core-concepts/exemptions#purpose-exemptions). ## Address resolution and validation The `/calculate` endpoint validates addresses against country-specific requirements before computing tax. ### Ship-to address resolution The destination address is resolved in the following order: 1. **`addresses.ship_to`** from the request body (highest priority). 2. **Customer's default shipping address** — used when `ship_to` is omitted and a `customer_id` is provided with a shipping address on file. 3. **Error** — if neither is available, the request returns a `400` error with sub-type `MISSING_SHIP_TO_ADDRESS`. ### Ship-from address The `ship_from` address is optional for most countries but required for certain destination countries (e.g., GB). If required but missing, the request returns a `400` error with sub-type `MISSING_SHIP_FROM_ADDRESS`. When a ship-from address is provided for US destinations, the state must be a valid US state code and the postal code must be a valid US ZIP format. ### Country-specific field validation Each address is validated against per-country requirements that define which fields are required, optional, or ignored. Only `country` is always required. All other fields — including `postal_code` and `state` — may be required, optional, or ignored depending on the country. Validation includes: * **Field presence** — required fields (e.g., `address_line_1`, `city` for US) must be provided and non-empty. * **State code validation** — the state must match one of the valid ISO 3166-2 subdivision codes for the country. * **Postal code format** — when a postal code is provided, it must match the country's expected format (e.g., `^\d{5}(-\d{4})?$` for US ZIP codes). The `postal_code` field is required for the US, EU countries (such as DE and FR), and GB. For CA, `postal_code` is optional but providing it improves tax jurisdiction accuracy. Use the [`/address-requirements`](/engine/indirect-tax/address-requirements/address-requirements) endpoint to query which fields and formats are expected for each country before calling `/calculate`. ## Multi-currency support The `/calculate` endpoint supports transactions in any [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) currency. You specify the currency of your transaction using the `transaction_currency` field, and all monetary values in the response are returned in that same currency. ### How it works When you submit a calculation, the engine applies tax rates in the **destination country's local currency**. If your `transaction_currency` differs from the destination country's default currency, the system automatically: 1. Converts your line item amounts into the destination country's currency. 2. Looks up and applies the correct tax rates in that local currency. 3. Converts the calculated tax amounts back into your `transaction_currency`. This means tax rates are always applied accurately in the jurisdiction's native currency, regardless of the currency your transaction is denominated in. ### Currency fields in the response | Field | Description | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `transaction_currency` | The currency you specified in the request. All amounts in the response (`total_amount`, `total_tax`, `total_due`, and line item amounts) are expressed in this currency. | | `tax_currency` | The currency in which tax amounts are expressed. This matches `transaction_currency`. | | `calculation_currency` | The destination country's default currency used internally to look up tax rates. Only present when a currency conversion occurred. | | `exchange_rate` | The exchange rate applied between `transaction_currency` and `calculation_currency`. Only present when a currency conversion occurred. | If you omit `transaction_currency` from your request, it defaults to the destination country's local currency (e.g., `USD` for the US, `GBP` for the UK, `EUR` for Germany). ### Monetary value rounding Amounts are rounded according to the ISO 4217 standard for each currency: * **Two decimal places** — most currencies (e.g., `USD`, `EUR`, `GBP`) * **Zero decimal places** — `JPY`, `KRW`, `HUF`, `CLP`, `IDR`, `VND`, `ISK`, `TWD` * **Three decimal places** — `BHD`, `KWD`, `OMR` ### Example: cross-currency calculation If you sell a product in `EUR` to a customer in the US, set `transaction_currency` to `EUR`. The engine converts the amounts to `USD` to calculate US sales tax, then converts the results back to `EUR`: ```json theme={null} { "transaction_currency": "EUR", "calculation_currency": "USD", "exchange_rate": 1.08, "total_amount": 100.00, "total_tax": 8.79, "total_due": 108.79 } ``` When both the transaction and destination use the same currency (e.g., `USD` transaction to a US address), no conversion occurs and `calculation_currency` and `exchange_rate` are omitted. ## Sample calculation object The `/calculate` endpoint returns a JSON object containing the transaction details and calculated taxes. Example response: ```json theme={null} { "data": { "id": "a7850851-be24-4c71-b9a3-3035e2d0c617", "corporation_id": "74df772f-9260-42cf-9c20-3b613b60fecd", "transaction_date": "2025-07-01", "transaction_currency": "USD", "discount": 0, "total_amount": 14338.01, "total_tax": 1190.05, "total_due": 15528.06, "customer_details": {}, "tax_currency": "USD", "addresses": { "ship_from": null, "ship_to": { "address_line_1": "123 N Central Ave", "address_line_2": "", "address_line_3": "", "postal_code": "85004", "city": "Phoenix city", "state": "AZ", "country": "US" } }, "line_items": [ { "line_item_id": "51f4ac30-e4f6-42e9-bb34-80305ea870b2", "amount": 14338.01, "taxable_amount": 14338.01, "quantity": 1, "tax_code": "TPP", "product_id": "", "line_number": 1, "effective_tax_rate": 8.3, "base_tax_rate": 9.1, "tax_breakdown": [ { "jurisdiction_name": "ARIZONA", "jurisdiction_type": "STATE_OR_PROVINCE", "rate": 5.6, "base_rate": 5.6, "tax_class": "TAXABLE", "tax_class_reason": "TAX_APPLIED" }, { "jurisdiction_name": "MARICOPA COUNTY", "jurisdiction_type": "COUNTY", "rate": 0.7, "base_rate": 0.7, "tax_class": "TAXABLE", "tax_class_reason": "TAX_APPLIED" }, { "jurisdiction_name": "PHOENIX CITY", "jurisdiction_type": "CITY", "rate": 2, "base_rate": 2.8, "tax_class": "TAXABLE", "tax_class_reason": "TAX_APPLIED" } ], "total_tax_due": 1190.05, "tax_collected": 0, "is_tax_included": false, "product_source_platform": "", "product_source_platform_id": "" } ] } } ``` # Calculate tax Source: https://docs.commenda.io/engine/indirect-tax/calculate/calculate-POST POST /calculate ```json US request theme={null} { "corporation_id": "b6d009b0-d174-463f-b030-94643c28e209", "transaction_date": "2023-12-25", "transaction_currency": "USD", "transaction_type": "SALE", "discount": 0, "addresses": { "ship_to": { "address_line_1": "1776 Main St", "address_line_2": "Apt. #123", "postal_code": "90401", "city": "Santa Monica", "state": "CA", "country": "US" }, "ship_from": { "address_line_1": "1776 Main St", "address_line_2": "Apt. #123", "postal_code": "90401", "city": "Santa Monica", "state": "CA", "country": "US" } }, "customer_details": { "customer_id": "customer_123" }, "line_items": { "items": [ { "line_number": 1, "product_taxability_code": "TPP", "quantity": 1, "amount": 100.00, "discount": 0, "product_id": "prod_123" } ] } } ``` ```json UK request theme={null} { "corporation_id": "b6d009b0-d174-463f-b030-94643c28e209", "transaction_date": "2025-04-01", "transaction_currency": "GBP", "transaction_type": "SALE", "discount": 0, "addresses": { "ship_to": { "address_line_1": "10 Downing Street", "postal_code": "SW1A 2AA", "city": "London", "country": "GB" }, "ship_from": { "address_line_1": "1 Canada Square", "postal_code": "E14 5AB", "city": "London", "country": "GB" } }, "customer_details": { "customer_id": "customer_456" }, "line_items": { "items": [ { "line_number": 1, "product_taxability_code": "TPP", "quantity": 1, "amount": 250.00, "discount": 0, "product_id": "prod_456" } ] } } ``` ```json Cross-currency request (EUR to US) theme={null} { "corporation_id": "b6d009b0-d174-463f-b030-94643c28e209", "transaction_date": "2025-04-01", "transaction_currency": "EUR", "transaction_type": "SALE", "discount": 0, "addresses": { "ship_to": { "address_line_1": "1776 Main St", "postal_code": "90401", "city": "Santa Monica", "state": "CA", "country": "US" } }, "customer_details": { "customer_id": "customer_789" }, "line_items": { "items": [ { "line_number": 1, "product_taxability_code": "TPP", "quantity": 1, "amount": 100.00, "discount": 0, "product_id": "prod_789" } ] } } ``` ```json 200 (same currency) theme={null} { "data": { "id": "calc_123", "corporation_id": "b6d009b0-d174-463f-b030-94643c28e209", "transaction_date": "2023-12-25", "transaction_currency": "USD", "discount": 0, "calculation_currency": "USD", "exchange_rate": 1.0, "total_amount": 100.00, "total_tax": 9.50, "total_due": 109.50, "customer_details": { "customer_id": "customer_123" }, "tax_currency": "USD", "addresses": { "ship_from": { "address_line_1": "1776 Main St", "address_line_2": "Apt. #123", "postal_code": "90401", "city": "Santa Monica", "state": "CA", "country": "US" }, "ship_to": { "address_line_1": "1776 Main St", "address_line_2": "Apt. #123", "postal_code": "90401", "city": "Santa Monica", "state": "CA", "country": "US" } }, "line_items": [ { "line_item_id": "line_123", "amount": 100.00, "taxable_amount": 100.00, "quantity": 1, "tax_code": "TPP", "product_id": "prod_123", "line_number": 1, "effective_tax_rate": 9.5, "base_tax_rate": 6.0, "tax_breakdown": [ { "jurisdiction_name": "California", "jurisdiction_type": "STATE", "rate": 6.0, "base_rate": 6.0, "tax_class": "TAXABLE", "tax_class_reason": "" }, { "jurisdiction_name": "Los Angeles County", "jurisdiction_type": "COUNTY", "rate": 2.25, "base_rate": 2.25, "tax_class": "TAXABLE", "tax_class_reason": "" }, { "jurisdiction_name": "Santa Monica", "jurisdiction_type": "CITY", "rate": 1.25, "base_rate": 1.25, "tax_class": "TAXABLE", "tax_class_reason": "" } ], "total_tax_due": 9.50 } ] }, "message": "Successfully calculated tax." } ``` ```json 200 Cross-currency response theme={null} { "data": { "id": "calc_456", "corporation_id": "b6d009b0-d174-463f-b030-94643c28e209", "transaction_date": "2025-04-01", "transaction_currency": "EUR", "discount": 0, "calculation_currency": "USD", "exchange_rate": 1.08, "total_amount": 100.00, "total_tax": 8.80, "total_due": 108.80, "customer_details": { "customer_id": "customer_789" }, "tax_currency": "EUR", "addresses": { "ship_from": null, "ship_to": { "address_line_1": "1776 Main St", "postal_code": "90401", "city": "Santa Monica", "state": "CA", "country": "US" } }, "line_items": [ { "line_item_id": "line_456", "amount": 100.00, "taxable_amount": 100.00, "quantity": 1, "tax_code": "TPP", "product_id": "prod_789", "line_number": 1, "effective_tax_rate": 9.5, "base_tax_rate": 6.0, "tax_breakdown": [ { "jurisdiction_name": "California", "jurisdiction_type": "STATE", "rate": 6.0, "base_rate": 6.0, "tax_class": "TAXABLE", "tax_class_reason": "TAX_APPLIED" }, { "jurisdiction_name": "Los Angeles County", "jurisdiction_type": "COUNTY", "rate": 2.25, "base_rate": 2.25, "tax_class": "TAXABLE", "tax_class_reason": "TAX_APPLIED" }, { "jurisdiction_name": "Santa Monica", "jurisdiction_type": "CITY", "rate": 1.25, "base_rate": 1.25, "tax_class": "TAXABLE", "tax_class_reason": "TAX_APPLIED" } ], "total_tax_due": 8.80 } ] }, "message": "Successfully calculated tax." } ``` ```json 400 Missing address theme={null} { "type": "INVALID_REQUEST_BODY", "sub_type": "MISSING_SHIP_TO_ADDRESS", "title": "Missing destination address.", "detail": { "description": "Missing destination address. Shipping address is picked from addresses.ship_to or picked from customer_details.customer_id (customer's default shipping address)." }, "status": 400 } ``` ```json 400 Invalid address theme={null} { "type": "INVALID_REQUEST_BODY", "sub_type": "INVALID_ADDRESS", "title": "Invalid address passed.", "detail": { "description": "Field 'city' is required for country US." }, "status": 400 } ``` # Exemptions Source: https://docs.commenda.io/engine/indirect-tax/core-concepts/exemptions ## Understanding Exemptions Many transactions may be partially or entirely exempt from sales tax. These exemptions can depend on factors such as the type of customer, product, or the intended purpose of the purchase. ### Product-Type Exemptions Certain products, like food and clothing, may be exempt from sales tax or subject to reduced rates in specific jurisdictions. The rules governing these exemptions are often complex. For instance, in Philadelphia, sweetened iced coffee is taxed unless more than 50% of its volume is milk. To manage these complexities, Commenda applies a conservative approach to global indirect tax calculations. When insufficient details are available to make a precise determination, Commenda defaults to the tax treatment with the higher rate to reduce audit risk. ### Purpose Exemptions Some buyers, such as wholesalers, may qualify for exemptions when purchasing goods for resale or specific purposes. ### Customer-Type Exemptions Certain customers, like government agencies or nonprofits, are typically exempt from sales tax in most situations. ## Exemption Certificates For both purpose and customer-type exemptions, sellers must collect exemption certificates from buyers. In the event of an audit, these certificates prove the seller was not required to collect sales tax on the transaction. You can manage exemption certificates at the customer level by calling our `/customers` collection of endpoints. # Global exposure tracking Source: https://docs.commenda.io/engine/indirect-tax/core-concepts/global-exposure Track registration threshold exposure across US, Canada, UK, and EU jurisdictions with support for trade bloc rules. ## Overview Commenda's exposure engine evaluates your transaction data against registration threshold rules for jurisdictions worldwide. It determines whether your business has exceeded — or is approaching — the point where you must register to collect and remit indirect tax in a given jurisdiction. The exposure engine supports: * **US economic thresholds** — state-level sales and transaction count thresholds (post-Wayfair) * **Canada GST/HST** — federal and provincial thresholds * **UK VAT** — standard UK VAT registration threshold * **EU country-level VAT** — per-country thresholds for EU member states * **EU trade bloc rules** — Union OSS, Non-Union OSS, and IOSS schemes with cross-border scope ## Key concepts ### Exposure rules Each jurisdiction has one or more exposure rules that define when registration is required. A rule specifies: | Field | Description | | ------------------------ | ---------------------------------------------------------------------------------------------------------- | | `exposure_rule_id` | Unique identifier for the rule | | `exposure_type` | The type of tax obligation (`EXPOSURE`, `EXPOSURE_ECONOMIC`, or `EXPOSURE_PHYSICAL`) | | `threshold_type` | Whether the threshold is based on `SALES_ONLY`, `SALES_OR_TRANSACTIONS`, or `SALES_AND_TRANSACTIONS` | | `sales_threshold` | Revenue amount that triggers registration | | `transactions_threshold` | Transaction count that triggers registration | | `evaluation_period_type` | Time window for measuring activity (e.g., `PRECEDING_12_MONTHS`, `PREVIOUS_OR_CURRENT_CALENDAR_YEAR`) | | `location_based_scope` | Which transactions count toward the threshold (`DESTINATION`, `WORLDWIDE`, `INTRA_COMMUNITY`, or `IMPORT`) | | `exclusion_types` | Transaction types excluded from threshold calculations (e.g., marketplace, B2B, resale) | | `establishment_types` | Business establishment types that determine which rule variant applies | | `max_transaction_value` | Maximum per-transaction value for inclusion (e.g., €150 for IOSS) | ### Multi-rule jurisdictions Some jurisdictions have multiple rules that apply based on your business's establishment status. For example, an EU member state may have: * A **resident rule** for businesses with a physical establishment in that country (e.g., office, warehouse) * A **non-resident rule** for businesses selling into the country without a local establishment The engine automatically selects the applicable rules based on your registered locations. ### Location-based scope Rules define which transactions count toward the threshold based on the geographic relationship between buyer and seller: | Scope | Description | | ----------------- | ------------------------------------------------------------------------------------------------------- | | `DESTINATION` | Transactions where the buyer is in the rule's jurisdiction | | `WORLDWIDE` | All transactions regardless of destination | | `INTRA_COMMUNITY` | Cross-border transactions within a trade bloc (e.g., EU seller to EU buyer in a different member state) | | `IMPORT` | Transactions where the seller is outside the trade bloc and the buyer is inside | ### Exclusions Certain transactions are automatically excluded from threshold calculations when the rule defines exclusions: * **Marketplace transactions** — sales facilitated by a marketplace that collects tax on your behalf * **B2B transactions** — sales to business customers identified by a business identification number (e.g., VAT number), which are typically subject to reverse charge * **Resale transactions** — sales to customers with valid resale certificates * **Product taxability** — specific product categories excluded per jurisdiction rules (e.g., tangible goods excluded from digital services thresholds) * **Destination registered** — transactions to jurisdictions where you are already registered ### Max transaction value (IOSS) The EU Import One-Stop Shop (IOSS) scheme applies only to consignments valued at or below €150. Transactions exceeding this cap are excluded from IOSS threshold tracking. An invoice exactly equal to the cap is included. ## Querying exposure data Use the registration thresholds endpoint with `v2=true` to retrieve exposure data across all supported jurisdictions: ```bash theme={null} curl -X GET "https://transaction-tax.api.in.commenda.io/api/v1/nexus?corporation_id={corporation_id}&v2=true" \ -H "Authorization: Bearer " ``` ### Response structure The v2 response returns an array of jurisdiction objects, each representing one exposure rule evaluation: ```json theme={null} { "data": { "corporation_id": "74df772f-9260-42cf-9c20-3b613b60fecd", "jurisdictions": [ { "jurisdiction_id": "STATE_US_NY_1036", "jurisdiction_type": "STATE", "jurisdiction_name": "New York", "exposure_type": "EXPOSURE_ECONOMIC", "exposure_rule_id": "us_ny_economic", "subdivision": "NY", "currency": "USD", "rule": { "sales_threshold": 500000, "transactions_threshold": null, "threshold_type": "SALES_ONLY", "evaluation_period_type": "PREVIOUS_OR_CURRENT_CALENDAR_YEAR", "location_based_scope": "DESTINATION", "exclusion_types": ["TRANSACTION.MARKETPLACE"], "establishment_types": [] }, "calculation": { "included_sales": 320000, "included_transactions": 1500, "gross_sales": 350000, "gross_transactions": 1800, "sales_exposure_percentage": 0.64, "transactions_exposure_percentage": 0 }, "is_nexus_breached": false, "recommended_registration_content_ids": ["REG_STATE_CEN_36"] }, { "jurisdiction_id": "TRADEBLOC_EU_3000", "jurisdiction_type": "TRADEBLOC", "jurisdiction_name": "EU Union OSS", "exposure_type": "EXPOSURE", "exposure_rule_id": "eu_union_oss", "subdivision": "", "currency": "EUR", "rule": { "sales_threshold": 10000, "transactions_threshold": null, "threshold_type": "SALES_ONLY", "evaluation_period_type": "PREVIOUS_OR_CURRENT_CALENDAR_YEAR", "location_based_scope": "INTRA_COMMUNITY", "exclusion_types": ["CUSTOMER.B2B"], "establishment_types": [], "max_transaction_value": 150 }, "calculation": { "included_sales": 8500, "included_transactions": 42, "gross_sales": 12000, "gross_transactions": 60, "sales_exposure_percentage": 0.85, "transactions_exposure_percentage": 0 }, "is_nexus_breached": false, "recommended_registration_content_ids": ["REG_TRADEBLOC_EU_3000_UOSS"] } ] }, "message": "Successfully fetched nexus." } ``` ### Response fields Each jurisdiction object includes: | Field | Description | | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `jurisdiction_id` | Internal identifier for the jurisdiction. For trade bloc rules, this is the trade bloc ID (e.g., `TRADEBLOC_EU_3000`) | | `jurisdiction_type` | `STATE`, `STATE_OR_PROVINCE`, `COUNTRY`, or `TRADEBLOC` | | `jurisdiction_name` | Human-readable name of the jurisdiction (e.g., "New York", "United Kingdom", "EU Union OSS") | | `exposure_type` | Type of exposure obligation: `EXPOSURE`, `EXPOSURE_ECONOMIC`, or `EXPOSURE_PHYSICAL` | | `exposure_rule_id` | Identifier for the specific rule being evaluated | | `subdivision` | State or province code, if applicable | | `currency` | Currency of the threshold amounts | | `rule` | The threshold rule being applied (see [Exposure rules](#exposure-rules) for field details) | | `calculation` | Your current progress toward the threshold | | `is_nexus_breached` | Whether you have exceeded the registration threshold | | `date_of_breach` | Date when the threshold was exceeded, if breached | | `recommended_registration_content_ids` | An array of V2 registration content IDs recommended for this jurisdiction (e.g., `["REG_STATE_CEN_06"]`). Use these with the [V2 Registration API](/engine/indirect-tax/registrations/v2/registrations-v2) to create a registration. | A single jurisdiction may appear multiple times in the response if multiple exposure rules apply (e.g., separate rules for goods and services in France or Ireland). ### Calculation fields | Field | Description | | ---------------------------------- | ---------------------------------------------------------------------- | | `included_sales` | Revenue counted toward the threshold after applying exclusions | | `included_transactions` | Transaction count after exclusions | | `gross_sales` | Total revenue before exclusions | | `gross_transactions` | Total transaction count before exclusions | | `sales_exposure_percentage` | Ratio of included sales to the sales threshold (0 to 1+) | | `transactions_exposure_percentage` | Ratio of included transactions to the transactions threshold (0 to 1+) | ## Triggering a sync The exposure engine runs automatically on a daily schedule and lazily on read. You can also trigger an on-demand recompute for a specific corporation via the public [Sync exposure](/engine/indirect-tax/nexus/exposure-sync-POST) endpoint: ```bash theme={null} curl -X POST "https://transaction-tax.api.in.commenda.io/api/v1/exposure/sync?corporation_id={corporation_id}" \ -H "Authorization: Bearer " ``` Every successful run emits an [`INDIRECT_TAX.EXPOSURE.COMPUTED`](/engine/indirect-tax/webhooks/event#indirect-tax-exposure) webhook with the corporation's full current set of exposed jurisdictions, so any subscribers stay in sync without polling. ## Physical presence If your business has a physical establishment (office, warehouse, or other location) in a jurisdiction, the engine evaluates resident rules for that jurisdiction. Resident rules may have different thresholds or no threshold at all — physical presence can trigger an immediate registration obligation. Register your business locations via the [Locations API](/engine/commendaos/locations) to ensure the engine correctly identifies which rules apply. # Registration thresholds Source: https://docs.commenda.io/engine/indirect-tax/core-concepts/nexus ## Understanding registration thresholds A registration threshold is the point at which a seller must register to collect and remit indirect tax in a given jurisdiction. Historically, this obligation was based primarily on physical presence. However, following the 2018 South Dakota v. Wayfair Supreme Court decision in the US, jurisdictions can now require remote sellers to collect and remit indirect tax based on their economic activity — commonly referred to as "economic thresholds." This concept applies globally: VAT and GST jurisdictions also set thresholds that determine when a business must register and begin collecting tax. Commenda tracks registration thresholds across US states, Canada, the UK, and the EU — including trade bloc rules like Union OSS, Non-Union OSS, and IOSS. See [global exposure tracking](/engine/indirect-tax/core-concepts/global-exposure) for details on multi-jurisdiction support and the v2 API. ### How jurisdictions define thresholds Each jurisdiction sets its own rules for determining when you must register, including: 1. **Threshold amounts:** Jurisdictions establish different sales and/or transaction thresholds that trigger a registration obligation. For example, one jurisdiction may have a USD 100,000 sales threshold, while another sets a EUR 10,000 threshold. 2. **Threshold types**: Some jurisdictions consider only sales revenue, some consider only the number of transactions, and some consider both. 3. **Evaluation periods**: The period over which economic activity is measured varies. Common periods include the previous calendar year, the current or previous calendar year, or a rolling 12-month period. ## Threshold tracking Commenda automatically tracks your progress toward registration thresholds in each jurisdiction based on the transactions you post to the `/transactions` endpoint. You can use the registration threshold API endpoint to get a comprehensive overview of your threshold status across all jurisdictions, taking into account each jurisdiction's specific rules. ### Default response (US states) By default, the `GET /nexus` endpoint returns US-state-level threshold data. The response contains a `states` array where each object represents your exposure in one US state. ```json theme={null} { "data": { "corporation_id": "74df772f-9260-42cf-9c20-3b613b60fecd", "states": [ { "state": "VT", "rule": { "sales_threshold": 100000, "transactions_threshold": 200, "threshold_type": "SALES_OR_TRANSACTIONS", "evaluation_period_type": "PRECEDING_12_MONTHS", "includable_sales_type": "GROSS" }, "calculation": { "total_sales": 0, "total_transactions": 0, "gross_sales": 0, "gross_transactions": 0, "taxable_sales": 0, "taxable_transactions": 0, "retail_sales": 0, "retail_transactions": 0, "sales_exposure_percentage": 0, "transactions_exposure_percentage": 0, "includable_sales_type": "GROSS" }, "is_nexus_breached": false } ] }, "message": "Successfully fetched nexus." } ``` The default response uses field names like `is_nexus_breached` and `states` for backward compatibility. These fields represent registration threshold status — `is_nexus_breached` indicates whether you have exceeded the registration threshold in a given jurisdiction. ### Global response (`v2=true`) Pass `v2=true` as a query parameter to get global jurisdiction-level threshold data. This covers US, Canada, UK, and EU jurisdictions, including support for multiple exposure rules per jurisdiction (for example, EU Union OSS, Non-Union OSS, and IOSS). The v2 response uses a `jurisdictions` array instead of `states`, and includes additional fields such as `jurisdiction_id`, `exposure_type`, `exposure_rule_id`, `subdivision`, and `currency`. ```json theme={null} { "data": { "corporation_id": "74df772f-9260-42cf-9c20-3b613b60fecd", "jurisdictions": [ { "jurisdiction_id": "US_CA_1000", "jurisdiction_type": "STATE", "jurisdiction_name": "California", "exposure_type": "EXPOSURE_ECONOMIC", "exposure_rule_id": "US_CA_ECONOMIC_001", "subdivision": "CA", "currency": "USD", "rule": { "sales_threshold": 500000, "transactions_threshold": null, "threshold_type": "SALES_ONLY", "evaluation_period_type": "PREVIOUS_OR_CURRENT_CALENDAR_YEAR", "location_based_scope": "DESTINATION", "exclusion_types": ["TRANSACTION.MARKETPLACE"], "establishment_types": [] }, "calculation": { "included_sales": 150000, "included_transactions": 320, "gross_sales": 175000, "gross_transactions": 350, "sales_exposure_percentage": 0.30, "transactions_exposure_percentage": 0 }, "is_nexus_breached": false, "recommended_registration_content_ids": ["REG_STATE_CEN_06_1000"] }, { "jurisdiction_id": "TRADEBLOC_EU_3000", "jurisdiction_type": "TRADEBLOC", "jurisdiction_name": "EU Union OSS", "exposure_type": "EXPOSURE", "exposure_rule_id": "EU_UNION_OSS_001", "subdivision": "", "currency": "EUR", "rule": { "sales_threshold": 10000, "transactions_threshold": null, "threshold_type": "SALES_ONLY", "evaluation_period_type": "PREVIOUS_OR_CURRENT_CALENDAR_YEAR", "location_based_scope": "INTRA_COMMUNITY", "exclusion_types": ["CUSTOMER.B2B"], "establishment_types": [], "max_transaction_value": 150 }, "calculation": { "included_sales": 12000, "included_transactions": 45, "gross_sales": 14000, "gross_transactions": 50, "sales_exposure_percentage": 1.20, "transactions_exposure_percentage": 0 }, "is_nexus_breached": true, "date_of_breach": "2026-03-15", "recommended_registration_content_ids": ["REG_TRADEBLOC_EU_3000_UOSS"] } ] }, "message": "Successfully fetched nexus." } ``` #### Recommended registration Each jurisdiction in the v2 response includes a `recommended_registration_content_ids` field: an array of content IDs that link directly to the [V2 Registration API](/engine/indirect-tax/registrations/v2/registrations-v2). When a threshold is breached (or approaching breach), use these IDs to discover the appropriate registration options via the [Available Registrations](/engine/indirect-tax/registrations/v2/content/available-registrations-POST) endpoint. #### Key differences from the default response | Field | Default | V2 (`v2=true`) | | --------------------------- | ----------------------------------------- | -------------------------------------------------------- | | Top-level array | `states` | `jurisdictions` | | Jurisdiction identifier | `state` (US state code) | `jurisdiction_id`, `subdivision` | | Currency | Implicitly USD | Explicit `currency` field | | Exposure rule metadata | Not included | `exposure_type`, `exposure_rule_id`, `jurisdiction_type` | | Calculation fields | `total_sales`, `total_transactions`, etc. | `included_sales`, `included_transactions`, etc. | | Registration recommendation | Not included | `recommended_registration_content_ids` | | Supported jurisdictions | US states only | US, Canada, UK, EU (country-level and tradebloc) | # Indirect Tax Transactions Source: https://docs.commenda.io/engine/indirect-tax/core-concepts/transactions Learn how to use the Commenda API to manage your taxes. ## Transactions Commenda provides a range of endpoints to manage transactions: 1. `/calculate` endpoint: * Used to estimate sales tax for a potential transaction. * The response includes the calculated tax amount. 2. `/transactions` endpoints: * Used to submit completed transactions to our system. * Commenda uses this data to file indirect tax in jurisdictions where the seller is registered and track the seller’s progress toward registration thresholds. * Supports both sales (`SALE`) and purchase (`PURCHASE`) transaction types. Purchase transactions are used for input tax credit calculations (EU VAT / UK VAT) and are excluded from sales-focused flows like threshold tracking and filings. 3. `/nexus` endpoint: * Used to view the seller’s progress toward registration thresholds. 4. `/registrations` endpoints: * Used to manage sales tax registrations. * Commenda uses information about registrations on the `/calculate` endpoint to determine if tax should be collected on transactions. 5. `/filings` endpoints: * View the contents and status of a seller's periodic sales tax filings. ## Typical Usage While the `/calculate` and `/transactions` endpoints can be used independently, a typical workflow is as follows:
  1. A customer visits your website, adds something to their cart, and clicks 'check out'.
  2. You call our `/calculate` API to determine the correct amount of sales tax to charge the customer.
  3. The customer pays the total amount, including the sales tax. You save the transaction details, including the subtotal and tax amount.
  4. After the transaction is completed, you call the `/transactions` API to submit the transaction details to our system.
## Discounts Typically, discounts are treated as a reduction in the overall sales price. To account for this, simply call our `/calculate` and `/transactions` endpoints using the post-discount price as the `amount` and `subtotal`. For accounting purposes, some customers may prefer to recognize the full sale amount and treat the discount as an expense. If you need this setup, please contact the Commenda team. # Corporations Source: https://docs.commenda.io/engine/indirect-tax/corporation/corporation Understand how Commenda's Global Indirect Tax API manages corporations for both single and multi-entity implementations. ## API Authentication for Partner vs. Business Implementations Each Commenda Global Indirect Tax API organization receives an API token, whether the organization manages multiple corporations (Partner Implementation) or a single corporation (Business Implementation). Include this token on each request as `Authorization: Bearer `. ## Corporations In Commenda's system, a corporation refers to a distinct legal entity or business that the API interacts with. Users can set up corporations in two main ways: * **Partner Implementations:** For users managing multiple businesses (such as merchants or clients), each entity they handle is treated as a separate corporation within the API. This is useful when different legal entities require separate records or compliance processes. * **Business Implementations:** For users building the API for their own company, only one corporation needs to be created, representing the user's business. ### Use Case Labels * **Partner Implementations:** For users managing multiple corporations. * **Business Implementations:** For users managing a single corporation for their own business. ## Corporations and Their Relationship with Other Resources Most resources in the system, such as customers, transactions, registrations, filings, and files, are linked to a specific corporation. When working with these resources, provide the `corporation_id` for context where the endpoint requires it. You can retrieve all corporations associated with your organization by using the `GET /corporations` endpoint. # Delete corporation Source: https://docs.commenda.io/engine/indirect-tax/corporation/corporation-DELETE DELETE /corporation/{id} Delete a corporation from your organization Deletes a corporation from your organization. This action cannot be undone. Deleting a corporation will remove all associated data. Ensure you have backed up any necessary information before proceeding. Unique identifier of the corporation to delete. ```bash cURL theme={null} curl --request DELETE \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/corporations/corp_123abc' \ --header 'Authorization: Bearer ' ``` ```javascript JavaScript theme={null} const response = await fetch('https://transaction-tax.api.in.commenda.io/api/v1/corporations/corp_123abc', { method: 'DELETE', headers: { 'Authorization': 'Bearer ' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.delete( 'https://transaction-tax.api.in.commenda.io/api/v1/corporations/corp_123abc', headers={'Authorization': 'Bearer '} ) data = response.json() ``` ```json 200 theme={null} { "message": "Corporation deleted successfully.", "data": { "id": "corp_123abc", "deleted": true } } ``` ```json 404 theme={null} { "error": { "code": "CORPORATION_NOT_FOUND", "message": "Corporation with the specified ID was not found" } } ``` ```json 409 theme={null} { "error": { "code": "CORPORATION_HAS_DEPENDENCIES", "message": "Cannot delete corporation with active transactions or registrations" } } ``` # List corporations Source: https://docs.commenda.io/engine/indirect-tax/corporation/corporation-GET-ALL GET /corporations Get all corporations in an organization Retrieves a paginated list of all corporations associated with your organization. Cursor for pagination. Use the cursor returned in the previous response to fetch the next page. Number of items to return per page. Must be between 1 and 100. Array of corporation objects. Unique identifier for the corporation. Legal name of the entity, including the type suffix. Unix timestamp of when the corporation was created. Jurisdiction of the corporation. Email alias for the corporation. Total number of corporations in the organization. Cursor to use for fetching the next page. Only present if there are more results. ```bash cURL theme={null} curl --request GET \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/corporations?limit=20' \ --header 'Authorization: Bearer ' ``` ```javascript JavaScript theme={null} const response = await fetch('https://transaction-tax.api.in.commenda.io/api/v1/corporations?limit=20', { method: 'GET', headers: { 'Authorization': 'Bearer ' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( 'https://transaction-tax.api.in.commenda.io/api/v1/corporations', params={'limit': 20}, headers={'Authorization': 'Bearer '} ) data = response.json() ``` ```json 200 theme={null} { "message": "Successfully fetched corporations.", "data": { "corporations": [ { "id": "corp_123abc", "legal_name": "Acme Corporation Inc.", "created_at": 1704067200, "jurisdiction": "US", "email_alias": "acme@filings.commenda.io" }, { "id": "corp_456def", "legal_name": "Example LLC", "created_at": 1704153600, "jurisdiction": "US" } ], "total_corporations": 2 } } ``` ```json 400 theme={null} { "error": { "code": "PAGINATION_INVALID_LIMIT", "message": "Limit must be between 1 and 100" } } ``` # Get email alias Source: https://docs.commenda.io/engine/indirect-tax/corporation/corporation-GET-EMAIL-ALIAS GET /corporations/{id}/email-alias Retrieve email addresses configured for a corporation's email alias Retrieves the list of email addresses that receive emails sent to the corporation's email alias. The unique identifier of the corporation. Array of email addresses that receive forwarded emails. ```bash cURL theme={null} curl --request GET \ --url https://transaction-tax.api.in.commenda.io/api/v1/corporations/{corporation_id}/email-alias \ --header 'Authorization: Bearer ' ``` ```javascript JavaScript theme={null} const response = await fetch('https://transaction-tax.api.in.commenda.io/api/v1/corporations/{corporation_id}/email-alias', { method: 'GET', headers: { 'Authorization': 'Bearer ' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( 'https://transaction-tax.api.in.commenda.io/api/v1/corporations/{corporation_id}/email-alias', headers={'Authorization': 'Bearer '} ) data = response.json() ``` ```json 200 theme={null} { "message": "Successfully fetched emails for email alias.", "data": { "emails": [ "accounting@example.com", "tax@example.com" ] } } ``` ```json 404 theme={null} { "error": { "code": "CORPORATION_EMAIL_ALIAS_NOT_FOUND", "message": "Email alias not found for corporation" } } ``` ```json 404 theme={null} { "error": { "code": "CORPORATION_NOT_FOUND", "message": "Corporation not found" } } ``` # Get corporation Source: https://docs.commenda.io/engine/indirect-tax/corporation/corporation-GET-ONE GET /corporations/{id} Retrieve a specific corporation by ID Retrieves the details of a specific corporation by its unique identifier. Unique identifier of the corporation to retrieve. Unique identifier for the corporation. Legal name of the entity, including the type suffix. Unix timestamp of when the corporation was created. Jurisdiction of the corporation. Email alias for the corporation. ```bash cURL theme={null} curl --request GET \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/corporations/corp_123abc' \ --header 'Authorization: Bearer ' ``` ```javascript JavaScript theme={null} const response = await fetch('https://transaction-tax.api.in.commenda.io/api/v1/corporations/corp_123abc', { method: 'GET', headers: { 'Authorization': 'Bearer ' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( 'https://transaction-tax.api.in.commenda.io/api/v1/corporations/corp_123abc', headers={'Authorization': 'Bearer '} ) data = response.json() ``` ```json 200 theme={null} { "message": "Corporation retrieved successfully.", "data": { "id": "corp_123abc", "legal_name": "Acme Corporation Inc.", "created_at": 1704067200, "jurisdiction": "US", "email_alias": "acme@filings.commenda.io" } } ``` ```json 404 theme={null} { "error": { "code": "CORPORATION_NOT_FOUND", "message": "Corporation with the specified ID was not found" } } ``` # Create corporation Source: https://docs.commenda.io/engine/indirect-tax/corporation/corporation-POST POST /corporations Create a new corporation in your organization Creates a new corporation entity in your organization. A corporation represents a distinct legal entity or business. Legal name of the entity, including the type suffix (e.g., "Inc.", "LLC"). The ISO 3166 2-alpha country code where the business entity is registered. ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/corporations' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "legal_name": "Acme Corporation Inc.", "jurisdiction": "US", "email_alias": "acme" }' ``` ```javascript JavaScript theme={null} const response = await fetch('https://transaction-tax.api.in.commenda.io/api/v1/corporations', { method: 'POST', headers: { 'Authorization': 'Bearer ', 'Content-Type': 'application/json' }, body: JSON.stringify({ legal_name: 'Acme Corporation Inc.', jurisdiction: 'US', email_alias: 'acme' }) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( 'https://transaction-tax.api.in.commenda.io/api/v1/corporations', headers={'Authorization': 'Bearer '}, json={ 'legal_name': 'Acme Corporation Inc.', 'jurisdiction': 'US', 'email_alias': 'acme' } ) data = response.json() ``` ```json 201 theme={null} { "message": "Corporation created successfully.", "data": { "id": "corp_123abc", "legal_name": "Acme Corporation Inc.", "created_at": 1704067200, "jurisdiction": "US", "email_alias": "acme@filings.commenda.io" } } ``` ```json 400 theme={null} { "error": { "code": "VALIDATION_ERROR", "message": "Invalid request body", "details": [ { "field": "legal_name", "message": "Legal name is required" } ] } } ``` ```json 409 theme={null} { "error": { "code": "CORPORATION_ALREADY_EXISTS", "message": "A corporation with this legal name already exists" } } ``` # Set email alias Source: https://docs.commenda.io/engine/indirect-tax/corporation/corporation-POST-EMAIL-ALIAS POST /corporations/{id}/email-alias Configure email forwarding for a corporation Sets the email addresses that will receive emails sent to the corporation's email alias. The email alias is used for filing-related communications. The unique identifier of the corporation. Array of email addresses to receive forwarded emails. Each email must be a valid email format. The email alias that was configured for the corporation. ```bash cURL theme={null} curl --request POST \ --url https://transaction-tax.api.in.commenda.io/api/v1/corporations/{corporation_id}/email-alias \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "emails": [ "accounting@example.com", "tax@example.com" ] }' ``` ```javascript JavaScript theme={null} const response = await fetch('https://transaction-tax.api.in.commenda.io/api/v1/corporations/{corporation_id}/email-alias', { method: 'POST', headers: { 'Authorization': 'Bearer ', 'Content-Type': 'application/json' }, body: JSON.stringify({ emails: [ 'accounting@example.com', 'tax@example.com' ] }) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( 'https://transaction-tax.api.in.commenda.io/api/v1/corporations/{corporation_id}/email-alias', headers={'Authorization': 'Bearer '}, json={ 'emails': [ 'accounting@example.com', 'tax@example.com' ] } ) data = response.json() ``` ```json 200 theme={null} { "message": "Successfully updated email alias.", "data": { "email_alias": "acme@filings.commenda.io" } } ``` ```json 400 theme={null} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Invalid email format" } } ``` ```json 404 theme={null} { "error": { "code": "CORPORATION_NOT_FOUND", "message": "Corporation not found" } } ``` # Update corporation Source: https://docs.commenda.io/engine/indirect-tax/corporation/corporation-UPDATE POST /corporations/{id} Update an existing corporation Updates the details of an existing corporation. Only the fields provided in the request will be updated. Unique identifier of the corporation to update. Legal name of the entity, including the type suffix (e.g., "Inc.", "LLC"). Jurisdiction where the corporation is registered (e.g., "US", "CA"). Custom email alias for the corporation. Unique identifier for the corporation. Legal name of the entity, including the type suffix. Unix timestamp of when the corporation was created. Jurisdiction of the corporation. Email alias for the corporation. ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/corporations/corp_123abc' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "legal_name": "Acme Corporation LLC", "jurisdiction": "US" }' ``` ```javascript JavaScript theme={null} const response = await fetch('https://transaction-tax.api.in.commenda.io/api/v1/corporations/corp_123abc', { method: 'POST', headers: { 'Authorization': 'Bearer ', 'Content-Type': 'application/json' }, body: JSON.stringify({ legal_name: 'Acme Corporation LLC', jurisdiction: 'US' }) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( 'https://transaction-tax.api.in.commenda.io/api/v1/corporations/corp_123abc', headers={'Authorization': 'Bearer '}, json={ 'legal_name': 'Acme Corporation LLC', 'jurisdiction': 'US' } ) data = response.json() ``` ```json 200 theme={null} { "message": "Corporation updated successfully.", "data": { "id": "corp_123abc", "legal_name": "Acme Corporation LLC", "created_at": 1704067200, "jurisdiction": "US", "email_alias": "acme@filings.commenda.io" } } ``` ```json 404 theme={null} { "error": { "code": "CORPORATION_NOT_FOUND", "message": "Corporation with the specified ID was not found" } } ``` ```json 400 theme={null} { "error": { "code": "VALIDATION_ERROR", "message": "Invalid request body", "details": [ { "field": "jurisdiction", "message": "Invalid jurisdiction code" } ] } } ``` # Credentials Source: https://docs.commenda.io/engine/indirect-tax/credentials/credentials Store and manage portal credentials for tax filing and compliance automation. ## Overview The Credentials API provides secure storage for login credentials to government tax portals. Credentials are used by Commenda to file tax returns on your behalf when managed filing is enabled on a registration. Each credential contains one or more **blocks** — structured key-value pairs that store individual fields like usernames, passwords, and account numbers. ## Credential types | Type | Description | | --------------------------- | ------------------------------------------------------------ | | `INDIRECT_TAX_REGISTRATION` | Credentials for a tax filing portal linked to a registration | | `OTHER` | General-purpose credentials | ## Block types | Type | Description | | -------------- | --------------------------------------------- | | `String` | Plain text value (usernames, account numbers) | | `SecureString` | Encrypted value (passwords, PINs) | | `File` | File attachment (certificates, keys) | ## Credential statuses | Status | Description | | --------- | ---------------------------------------- | | `ACTIVE` | Credential is valid and in use | | `EXPIRED` | Credential has expired and needs renewal | ## Workflow Use the [Portal Fields](/engine/indirect-tax/registrations/v2/content/portal-fields-POST) endpoint to see what credential fields a portal requires. Use the [Create Credential](/engine/indirect-tax/credentials/credentials-POST) endpoint to store the portal login details. Pass the `credential_id` when [creating](/engine/indirect-tax/registrations/v2/registrations-v2-POST) or [updating](/engine/indirect-tax/registrations/v2/registrations-v2-id-POST) a V2 registration. ## API endpoints | Endpoint | Method | Description | | ----------------------------------------------------------------------------- | ------ | ---------------------------------- | | [`/credentials`](/engine/indirect-tax/credentials/credentials-POST) | POST | Create a new credential | | [`/credentials`](/engine/indirect-tax/credentials/credentials-GET) | GET | List credentials for a corporation | | [`/credentials/{id}`](/engine/indirect-tax/credentials/credentials-id-GET) | GET | Get a single credential | | [`/credentials/{id}`](/engine/indirect-tax/credentials/credentials-id-POST) | POST | Update a credential | | [`/credentials/{id}`](/engine/indirect-tax/credentials/credentials-id-DELETE) | DELETE | Delete a credential | ## Extending list responses When listing credentials, you can include additional portal details by passing `extend=PORTAL_DETAILS` as a query parameter. This adds the portal name, URL, and jurisdiction information to each credential in the response. # List credentials Source: https://docs.commenda.io/engine/indirect-tax/credentials/credentials-GET GET https://transaction-tax.api.in.commenda.io/api/v1/credentials List all credentials for a corporation Retrieve all credentials belonging to a corporation. Optionally filter by portal IDs and include inactive credentials. ## Query parameters The unique identifier (UUID) for the corporation. Comma-separated list of portal IDs to filter by. Example: `PORTAL_CA_CDTFA,PORTAL_TX_CPTD` Set to `true` to include expired credentials. Defaults to `false`. Set to `PORTAL_DETAILS` to include portal name, URL, and jurisdiction information in the response. ```bash cURL theme={null} curl --request GET \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/credentials?corporation_id=550e8400-e29b-41d4-a716-446655440000&extend=PORTAL_DETAILS' \ --header 'Authorization: Bearer ' ``` ```json 200 theme={null} { "message": "Successfully listed credentials.", "data": { "credentials": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "portal_id": "PORTAL_CA_CDTFA", "credential_type": "INDIRECT_TAX_REGISTRATION", "is_custom": false, "name": "California CDTFA Portal", "status": "ACTIVE", "blocks": [ { "id": "block-uuid-1", "block_key": "username", "block_label": "Username", "block_type": "String" }, { "id": "block-uuid-2", "block_key": "password", "block_label": "Password", "block_type": "SecureString" } ], "portal_details": { "portal_id": "PORTAL_CA_CDTFA", "portal_name": "California Department of Tax and Fee Administration", "portal_url": "https://onlineservices.cdtfa.ca.gov", "country": "US", "state_or_province": "CA" }, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" } ], "count": 1 } } ``` ```json 200 - Empty theme={null} { "message": "Successfully listed credentials.", "data": { "credentials": [], "count": 0 } } ``` Block values for `SecureString` types are not returned in list responses. Use the [Get Credential](/engine/indirect-tax/credentials/credentials-id-GET) endpoint to retrieve a specific credential with its values. # Create credential Source: https://docs.commenda.io/engine/indirect-tax/credentials/credentials-POST POST https://transaction-tax.api.in.commenda.io/api/v1/credentials Create a new credential for storing portal login information Create a credential to store login details for a government tax portal. Use the [Portal Fields](/engine/indirect-tax/registrations/v2/content/portal-fields-POST) endpoint to discover what fields a portal requires. ## Request body The unique identifier (UUID) for the corporation. The type of credential. Values: `INDIRECT_TAX_REGISTRATION`, `OTHER`. Array of credential blocks. Each block stores one field (e.g., username, password). Minimum 1 block required. Each block requires: * `block_key` — unique key for the field (e.g., `username`) * `block_label` — display label (e.g., `Username`) * `block_type` — one of `String`, `SecureString`, `File` * `value` — the field value The portal ID to associate the credential with. Get this from the [Portal Fields](/engine/indirect-tax/registrations/v2/content/portal-fields-POST) endpoint. A display name for the credential. URL of the tax portal. Optional notes about the credential. Whether this is a custom (user-defined) credential rather than a portal-driven one. ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/credentials' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "credential_type": "INDIRECT_TAX_REGISTRATION", "portal_id": "PORTAL_CA_CDTFA", "name": "California CDTFA Portal", "blocks": [ { "block_key": "username", "block_label": "Username", "block_type": "String", "value": "user@example.com" }, { "block_key": "password", "block_label": "Password", "block_type": "SecureString", "value": "my-secure-password" } ] }' ``` ```json Standard theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "credential_type": "INDIRECT_TAX_REGISTRATION", "portal_id": "PORTAL_CA_CDTFA", "name": "California CDTFA Portal", "blocks": [ { "block_key": "username", "block_label": "Username", "block_type": "String", "value": "user@example.com" }, { "block_key": "password", "block_label": "Password", "block_type": "SecureString", "value": "my-secure-password" } ] } ``` ```json 201 theme={null} { "message": "Successfully created credential.", "data": { "credential": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" } } } ``` ```json 400 - Invalid credential type theme={null} { "message": "Validation failed.", "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Failed to validate the request body", "detail": { "description": "invalid credential_type: INVALID" }, "status": 400, "instance": "/api/v1/credentials" } } ``` ```json 400 - Invalid block type theme={null} { "message": "Validation failed.", "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Failed to validate the request body", "detail": { "description": "blocks[0]: invalid block_type: INVALID" }, "status": 400, "instance": "/api/v1/credentials" } } ``` # Delete credential Source: https://docs.commenda.io/engine/indirect-tax/credentials/credentials-id-DELETE DELETE https://transaction-tax.api.in.commenda.io/api/v1/credentials/{id} Delete a credential Delete a credential. This operation fails if the credential is linked to any active registrations — unlink the credential from all registrations first. ## Path parameters The unique identifier (UUID) of the credential to delete. ```bash cURL theme={null} curl --request DELETE \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/credentials/a1b2c3d4-e5f6-7890-abcd-ef1234567890' \ --header 'Authorization: Bearer ' ``` ```json 200 theme={null} { "message": "Successfully deleted credential.", "data": { "credential": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "deleted": true } } } ``` ```json 404 - Not found theme={null} { "error": { "type": "CREDENTIAL_NOT_FOUND", "title": "Credential not found.", "detail": { "description": "The credential does not exist or you don't have access." }, "status": 404, "instance": "/api/v1/credentials/a1b2c3d4-e5f6-7890-abcd-ef1234567890" } } ``` ```json 400 - Has active registrations theme={null} { "error": { "type": "CREDENTIAL_HAS_ACTIVE_REGISTRATIONS", "title": "Cannot delete credential with active registrations.", "detail": { "description": "This credential is linked to one or more active registrations. Remove the credential from all registrations before deleting." }, "status": 400, "instance": "/api/v1/credentials/a1b2c3d4-e5f6-7890-abcd-ef1234567890" } } ``` # Get credential Source: https://docs.commenda.io/engine/indirect-tax/credentials/credentials-id-GET GET https://transaction-tax.api.in.commenda.io/api/v1/credentials/{id} Retrieve a specific credential by ID Retrieve the full details of a credential, including its blocks. ## Path parameters The unique identifier (UUID) of the credential. ```bash cURL theme={null} curl --request GET \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/credentials/a1b2c3d4-e5f6-7890-abcd-ef1234567890' \ --header 'Authorization: Bearer ' ``` ```json 200 theme={null} { "message": "Successfully retrieved credential.", "data": { "credential": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "portal_id": "PORTAL_CA_CDTFA", "credential_type": "INDIRECT_TAX_REGISTRATION", "is_custom": false, "name": "California CDTFA Portal", "status": "ACTIVE", "blocks": [ { "id": "block-uuid-1", "block_key": "username", "block_label": "Username", "block_type": "String", "value": "user@example.com" }, { "id": "block-uuid-2", "block_key": "password", "block_label": "Password", "block_type": "SecureString", "value": "my-secure-password" } ], "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" } } } ``` ```json 404 - Not found theme={null} { "error": { "type": "CREDENTIAL_NOT_FOUND", "title": "Credential not found.", "detail": { "description": "The credential does not exist or you don't have access." }, "status": 404, "instance": "/api/v1/credentials/a1b2c3d4-e5f6-7890-abcd-ef1234567890" } } ``` # Update credential Source: https://docs.commenda.io/engine/indirect-tax/credentials/credentials-id-POST POST https://transaction-tax.api.in.commenda.io/api/v1/credentials/{id} Update an existing credential and its blocks Update a credential's details and blocks. You can add new blocks, update existing ones, and delete blocks by ID. ## Path parameters The unique identifier (UUID) of the credential to update. ## Request body The unique identifier (UUID) for the corporation. The portal ID to associate the credential with. Updated display name. Updated portal URL. Updated notes. Updated status. Values: `ACTIVE`, `EXPIRED`. Array of blocks to add or update. Each block requires `block_key`, `block_label`, `block_type`, and `value`. Include `id` for existing blocks to update them; omit `id` to create new blocks. Array of block IDs to delete from this credential. ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/credentials/a1b2c3d4-e5f6-7890-abcd-ef1234567890' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "name": "California CDTFA Portal (Updated)", "blocks": [ { "id": "block-uuid-1", "block_key": "username", "block_label": "Username", "block_type": "String", "value": "new-user@example.com" } ] }' ``` ```json Update blocks theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "name": "California CDTFA Portal (Updated)", "blocks": [ { "id": "block-uuid-1", "block_key": "username", "block_label": "Username", "block_type": "String", "value": "new-user@example.com" } ] } ``` ```json Delete blocks theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "blocks_to_delete": ["block-uuid-2"] } ``` ```json 200 theme={null} { "message": "Successfully updated credential.", "data": { "credential": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "updated_at": "2024-02-01T14:00:00Z" } } } ``` ```json 404 - Not found theme={null} { "error": { "type": "CREDENTIAL_NOT_FOUND", "title": "Credential not found.", "detail": { "description": "The credential does not exist or you don't have access." }, "status": 404, "instance": "/api/v1/credentials/a1b2c3d4-e5f6-7890-abcd-ef1234567890" } } ``` # Customers Source: https://docs.commenda.io/engine/indirect-tax/customers/customer Manage customers and their exemption certificates. ## Overview Customers represent the purchasers of goods sold by the merchant. You can manage exemption certificates on their behalf. ### Business identification number You can store a tax or business registration number on each customer using the `business_identification_number` field. This is useful for recording identifiers such as VAT IDs, EINs, or GST numbers that may be required for tax compliance in certain jurisdictions. The field is optional and can be set when [creating](/engine/indirect-tax/customers/customers-POST) or [updating](/engine/indirect-tax/customers/customers-id-POST) a customer. ### Exemption certificates Customers may claim sales tax exemptions based on the purpose of the purchase (e.g., wholesale) or their entity type (e.g., nonprofit). When a customer claims an exemption, the merchant is required to collect proof that the customer is eligible for the exemption in the form of exemption certificates. Learn more about exemption certificates [here](/engine/indirect-tax/core-concepts/exemptions#exemption-certificates). After an exemption certificate is uploaded, Commenda records its review state in the `verification_status` field. Tax calculation is controlled by the certificate's active jurisdiction exemptions, effective dates, and expiration settings. If Commenda marks a certificate `VERIFICATION_FAILED`, its jurisdiction exemptions are deactivated. # List customers Source: https://docs.commenda.io/engine/indirect-tax/customers/customers-GET GET /customers List customers associated with a corporation. Retrieves a paginated list of customers for a corporation with optional filtering and search capabilities. ## Query parameters The unique identifier for the corporation Pagination cursor for fetching the next page of results Maximum number of customers to return (max: 100) Filter customers by exact name match Search customers by name (partial match) Comma-separated list of source platforms to filter by Comma-separated list of source platform IDs to filter by Comma-separated list of fields to include in response. Options: `shipping_address`, `exemption_metadata` ### Exemption filters Comma-separated list of certificate types to filter by Filter by exemption jurisdiction Filter by certificate expiration status Filter by exemption status Filter customers by whether they have exemptions ## Response Array of customer objects Unique identifier for the customer Customer name Customer email address The corporation ID this customer belongs to Unix timestamp of when the customer was created Source platform identifier (if applicable) Source platform name (if applicable) The customer's tax or business registration number, if provided Customer's shipping address (included when `extend=shipping_address`) Street address line 1 Street address line 2 City name State or province code Postal or ZIP code ISO 3166 2-letter country code Exemption information (included when `extend=exemption_metadata`) Total number of customers matching the query Pagination cursor for the next page (if more results exist) ```bash theme={null} GET /customers?corporation_id=corp_123&limit=20&extend=shipping_address&search_term=acme ``` ```json theme={null} { "customers": [ { "id": "cust_789", "name": "Acme Corporation", "email": "contact@acme.com", "corporation_id": "corp_123", "created_at": 1706000000, "shipping_address": { "line1": "123 Main St", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" } } ], "total_customers": 1, "cursor": null } ``` # Create customer Source: https://docs.commenda.io/engine/indirect-tax/customers/customers-POST POST /customers Create a customer to track their exemption certificates and default values for their addresses. Creates a new customer for a corporation. ## Request body The unique identifier for the corporation Customer name (minimum 3 characters) Customer email address (must be valid email format) External identifier for the customer from your system A tax or business registration number for the customer (e.g., VAT ID, EIN, GST number). Used to identify the customer's tax status in applicable jurisdictions. Customer's shipping address Street address line 1 Street address line 2 City name State or province code Postal or ZIP code ISO 3166 2-letter country code ## Response Unique identifier for the customer Customer name Customer email address The corporation ID this customer belongs to Unix timestamp of when the customer was created Source platform identifier (if applicable) Source platform name (if applicable) The customer's tax or business registration number, if provided ```json theme={null} { "corporation_id": "corp_123", "name": "Acme Corporation", "email": "contact@acme.com", "external_id": "ext_456", "business_identification_number": "12-3456789", "shipping_address": { "line1": "123 Main St", "line2": "Suite 100", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" } } ``` ```json theme={null} { "id": "cust_789", "name": "Acme Corporation", "email": "contact@acme.com", "corporation_id": "corp_123", "created_at": 1706000000 } ``` # Delete customer Source: https://docs.commenda.io/engine/indirect-tax/customers/customers-id-DELETE DELETE /customers/{id} Deletes a customer by its id Deletes a customer from the system. ## Path parameters The unique identifier for the customer to delete ## Response Returns HTTP 204 No Content on successful deletion. ```bash theme={null} DELETE /customers/cust_789 ``` ```text theme={null} 204 No Content ``` # Get customer Source: https://docs.commenda.io/engine/indirect-tax/customers/customers-id-GET GET /customers/{id} Get detailed information about a specific customer, including exemption certificates. Retrieves detailed information about a specific customer. ## Path parameters The unique identifier for the customer ## Response Unique identifier for the customer Customer name Customer email address The corporation ID this customer belongs to Unix timestamp of when the customer was created Source platform identifier (if applicable) Source platform name (if applicable) The customer's tax or business registration number, if provided Customer's shipping address Street address line 1 Street address line 2 City name State or province code Postal or ZIP code ISO 3166 2-letter country code Exemption certificate information for the customer ```bash theme={null} GET /customers/cust_789 ``` ```json theme={null} { "id": "cust_789", "name": "Acme Corporation", "email": "contact@acme.com", "corporation_id": "corp_123", "created_at": 1706000000, "shipping_address": { "line1": "123 Main St", "line2": "Suite 100", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" } } ``` # Update customer Source: https://docs.commenda.io/engine/indirect-tax/customers/customers-id-POST POST /customers/{id} Update a customer, including their addresses and exemption certificates. Updates an existing customer's information. ## Path parameters The unique identifier for the customer ## Request body Customer name (minimum 3 characters) Customer email address (must be valid email format) A tax or business registration number for the customer (e.g., VAT ID, EIN, GST number). Customer's shipping address Street address line 1 Street address line 2 City name State or province code Postal or ZIP code ISO 3166 2-letter country code ## Response Returns a success message upon successful update. ```json theme={null} { "name": "Acme Corporation Updated", "email": "newemail@acme.com", "business_identification_number": "12-3456789", "shipping_address": { "line1": "456 New St", "line2": "Floor 2", "city": "Los Angeles", "state": "CA", "postal_code": "90001", "country": "US" } } ``` ```json theme={null} { "message": "Customer updated successfully" } ``` # Exemption Certificates Source: https://docs.commenda.io/engine/indirect-tax/exemptions/exemption-certificates/exemption-certificates Manage exemption certificates for a customer. ## Overview Exemption certificates are legal documents that allow specific buyers to purchase goods or services without paying sales tax. Merchants can use Commenda to create and manage exemption certificates for their customers. ## How to create an exemption certificate To create an exemption certificate, follow these steps: 1. **Create a Customer Record:** Use the customer endpoint to create a customer record, which will be linked to the exemption certificate. Save the `customer ID` from the response. Learn more about customer creation [here](/engine/indirect-tax/customers/customer). 2. **Upload the Certificate File:** Use the file endpoint to upload the exemption certificate document and save the returned file ID. Details on how to use the file endpoint can be found [here](/engine/indirect-tax/files/files). 3. **Link Customer and File:** Use the `POST /exemption-certificates` endpoint to link the customer and the uploaded file, thereby creating the exemption certificate. ## Certificate types 1. **Single state**: This type of exemption certificate is valid only within a single state. Each state has specific rules regarding which entities can claim exemptions and the process for doing so. 2. **SST**: This is a [Streamlined Sales Tax exemption certificate](https://www.streamlinedsalestax.org/Shared-Pages/exemptions-). It may be recognized in multiple states, including any states that are members of the Streamlined Sales Tax Governing Board. 3. **MTC**: This is a [Multistate Tax Commission exemption certificate](https://www.mtc.gov/resources/uniform-sales-use-tax-exemption-certificate). It may be recognized in multiple states, including any of the 36 states which are are part of the Multistate Tax Commission. ## Certificate review status Exemption certificates include a `verification_status` field so Commenda can surface the review state of a certificate. When a certificate is created with a `file_id`, its initial status is `VERIFICATION_PENDING`. Certificates created without a file are marked `NOT_READY` until a file is attached. Tax calculation is based on active jurisdiction exemptions, effective dates, and expiration settings. Do not use `verification_status` alone to predict tax treatment. If Commenda marks a certificate `VERIFICATION_FAILED`, the certificate's jurisdiction exemptions are deactivated. When Commenda updates a certificate to `VERIFICATION_SUCCESS` or `VERIFICATION_FAILED`, the corresponding exemption certificate webhook is sent. For more details, see [exemption certificate webhooks](/engine/indirect-tax/webhooks/event#exemptions-certificates). # Delete exemption certificate Source: https://docs.commenda.io/engine/indirect-tax/exemptions/exemption-certificates/exemption-certificates-DELETE DELETE /exemption-certificates/{id} Delete an exemption certificate. This does not delete the associated file. ## Path parameters The unique identifier of the exemption certificate to delete. ## Response Returns a 204 No Content status code on successful deletion. Success message confirming the deletion. Deleting an exemption certificate will remove it and all associated jurisdiction exemptions. However, any files that were attached to the certificate will remain in the system and must be deleted separately if needed. # List exemption certificates Source: https://docs.commenda.io/engine/indirect-tax/exemptions/exemption-certificates/exemption-certificates-GET GET /exemption-certificates Get a paginated list of all exemption certificates for a specific customer ## Query parameters The unique identifier of the customer whose exemption certificates you want to retrieve. Number of exemption certificates to return per page. Must be between 1 and 100. Pagination cursor for fetching the next page of results. Obtained from the previous response. ## Response Array of exemption certificate objects. Unique identifier for the exemption certificate. The customer ID this certificate belongs to. The file ID associated with this certificate, if any. The type of exemption certificate (SINGLE\_STATE, MULTI\_STATE, or BLANKET). Current verification status of the certificate: `NOT_READY`, `VERIFICATION_PENDING`, `VERIFICATION_SUCCESS`, or `VERIFICATION_FAILED`. The certificate number, if provided. The effective date of the certificate (ISO 8601 date). Unix timestamp when the certificate was created. Array of jurisdiction exemptions associated with this certificate. Total count of exemption certificates for this customer. Cursor for fetching the next page of results. Empty if no more results. Success message. # Get exemption certificate Source: https://docs.commenda.io/engine/indirect-tax/exemptions/exemption-certificates/exemption-certificates-GET-ONE GET /exemption-certificates/{id} Retrieve a specific exemption certificate by its unique identifier ## Path parameters The unique identifier of the exemption certificate to fetch. ## Response Unique identifier for the exemption certificate. The customer ID this certificate belongs to. The file ID associated with this certificate, if any. The type of exemption certificate (SINGLE\_STATE, MULTI\_STATE, or BLANKET). Current verification status of the certificate: * `NOT_READY`: No certificate file is attached * `VERIFICATION_PENDING`: Awaiting verification * `VERIFICATION_SUCCESS`: Successfully verified * `VERIFICATION_FAILED`: Verification failed The certificate number, if provided. The effective date of the certificate (ISO 8601 date). Unix timestamp when the certificate was created. Array of jurisdiction exemptions associated with this certificate. ISO 3166-1 alpha-2 country code. ISO 3166-2 subdivision code. Reason for the exemption. Whether the exemption is currently active. Expiration date, if applicable. Type of identification used. The identification number. Whether the exemption has expired. Unix timestamp when the jurisdiction exemption was created. Success message. # Create exemption certificate Source: https://docs.commenda.io/engine/indirect-tax/exemptions/exemption-certificates/exemption-certificates-POST POST /exemption-certificates Create an exemption certificate for a customer with one or more jurisdiction exemptions ## Request body The unique identifier of the customer this exemption certificate belongs to. The unique identifier of the file associated with this exemption certificate (e.g., scanned certificate document). The date when the exemption certificate becomes effective. Format: ISO 8601 date (YYYY-MM-DD). The type of exemption certificate. Valid values: * `SINGLE_STATE`: Certificate valid for a single state (maximum 1 jurisdiction) * `MULTI_STATE`: Certificate valid for multiple states * `BLANKET`: Blanket exemption certificate The certificate number assigned by the issuing authority. Maximum 20 characters. Array of jurisdiction exemptions. Must contain at least one jurisdiction. Type of identification. Valid values: * `FEIN`: Federal Employer Identification Number * `STATE_ISSUED_EXEMPTION_ID`: State-issued exemption ID * `DRIVERS_LICENSE`: Driver's license * `FOREIGN_DIPLOMAT_ID`: Foreign diplomat ID The identification number corresponding to the identification type. ISO 3166-1 alpha-2 country code (e.g., "US"). Currently only US is supported. ISO 3166-2 subdivision code (e.g., "CA", "NY", "TX"). Reason for the exemption. Valid values: * `PURPOSE_RESALE`: Resale exemption * `PURPOSE_MANUFACTURING`: Manufacturing exemption * `PURPOSE_AGRICULTURE`: Agricultural exemption * `ENTITY_GOVERNMENT`: Government entity * `ENTITY_NONPROFIT`: Non-profit organization * `ENTITY_EDUCATION`: Educational institution * `ENTITY_RELIGIOUS`: Religious organization Optional expiration date for the exemption. Format: ISO 8601 date (YYYY-MM-DD). Whether the exemption is currently active. Defaults to true if not specified. ## Response Unique identifier for the exemption certificate. The customer ID this certificate belongs to. The file ID associated with this certificate, if any. The type of exemption certificate (SINGLE\_STATE, MULTI\_STATE, or BLANKET). Current verification status of the certificate: * `NOT_READY`: No certificate file is attached * `VERIFICATION_PENDING`: Awaiting verification * `VERIFICATION_SUCCESS`: Successfully verified * `VERIFICATION_FAILED`: Verification failed The certificate number, if provided. The effective date of the certificate (ISO 8601 date). Unix timestamp when the certificate was created. Array of jurisdiction exemptions associated with this certificate. ISO 3166-1 alpha-2 country code. ISO 3166-2 subdivision code. Reason for the exemption. Whether the exemption is currently active. Expiration date, if applicable. Type of identification used. The identification number. Whether the exemption has expired. Unix timestamp when the jurisdiction exemption was created. Success message. # Update exemption certificate Source: https://docs.commenda.io/engine/indirect-tax/exemptions/exemption-certificates/exemption-certificates-UPDATE POST /exemption-certificates/{exemption_certificate_id} Update an existing exemption certificate Updates specific fields of an exemption certificate. At least one field must be provided for update. The unique identifier of the exemption certificate to update. The effective date of the exemption certificate in ISO 8601 format (YYYY-MM-DD). The exemption certificate number. Maximum 20 characters. The ID of the file associated with this exemption certificate. ```json 200 theme={null} { "message": "Successfully updated exemption certificate." } ``` ```json 400 theme={null} { "error": { "code": "INVALID_REQUEST_BODY", "message": "At least one field must be provided for update" } } ``` ```json 404 theme={null} { "error": { "code": "EXEMPTION_CERTIFICATE_NOT_FOUND", "message": "Exemption certificate not found" } } ``` ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "effective_date": "2024-01-01", "exemption_certificate_number": "EX-12345" }' ``` ```javascript JavaScript theme={null} const response = await fetch('https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}', { method: 'POST', headers: { 'Authorization': 'Bearer ', 'Content-Type': 'application/json' }, body: JSON.stringify({ effective_date: '2024-01-01', exemption_certificate_number: 'EX-12345' }) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( 'https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}', headers={'Authorization': 'Bearer '}, json={ 'effective_date': '2024-01-01', 'exemption_certificate_number': 'EX-12345' } ) data = response.json() ``` # Bulk delete jurisdiction exemptions Source: https://docs.commenda.io/engine/indirect-tax/exemptions/exemption-certificates/jurisdictions-BULK-DELETE DELETE /exemption-certificates/{exemption_certificate_id}/jurisdictions/bulk_delete Delete multiple jurisdiction exemptions at once Deletes multiple jurisdiction exemptions from an exemption certificate in a single request. The unique identifier of the exemption certificate. Array of jurisdiction identifiers to delete. Each jurisdiction must be in the format `{country}_{state}` (e.g., "US\_CA" for California). ```json 200 theme={null} { "message": "Successfully deleted exemptions." } ``` ```json 400 theme={null} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Invalid jurisdiction format. Expected format: {country}_{state}" } } ``` ```json 404 theme={null} { "error": { "code": "EXEMPTION_CERTIFICATE_NOT_FOUND", "message": "Exemption certificate not found" } } ``` ```bash cURL theme={null} curl --request DELETE \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}/jurisdictions/bulk_delete' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "jurisdictions": ["US_CA", "US_NY", "US_TX"] }' ``` ```javascript JavaScript theme={null} const response = await fetch('https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}/jurisdictions/bulk_delete', { method: 'DELETE', headers: { 'Authorization': 'Bearer ', 'Content-Type': 'application/json' }, body: JSON.stringify({ jurisdictions: ['US_CA', 'US_NY', 'US_TX'] }) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.delete( 'https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}/jurisdictions/bulk_delete', headers={'Authorization': 'Bearer '}, json={ 'jurisdictions': ['US_CA', 'US_NY', 'US_TX'] } ) data = response.json() ``` # Bulk upsert jurisdiction exemptions Source: https://docs.commenda.io/engine/indirect-tax/exemptions/exemption-certificates/jurisdictions-BULK-UPSERT POST /exemption-certificates/{exemption_certificate_id}/jurisdictions/bulk_upsert Create or update multiple jurisdiction exemptions at once Creates or updates multiple jurisdiction exemptions for an exemption certificate in a single request. If a jurisdiction already exists, it will be updated; otherwise, it will be created. The unique identifier of the exemption certificate. Array of jurisdiction exemptions to upsert. Each jurisdiction must be unique. ISO 3166-1 alpha-2 country code. Currently only "US" is supported. ISO 3166-2 subdivision code (e.g., "CA" for California). The reason for the exemption. Valid values: * `PURPOSE_RESALE` * `ENTITY_TYPE_NON_PROFIT` * `GOVERNMENT` * `MANUFACTURER` * `AGRICULTURAL` * `OTHER` The type of identification for the exemption. The identification number for the exemption. The end date of the exemption in ISO 8601 format (YYYY-MM-DD). Whether the exemption is active. ```json 200 theme={null} { "message": "Successfully updated exemptions." } ``` ```json 400 theme={null} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Duplicate jurisdictions found in request" } } ``` ```json 404 theme={null} { "error": { "code": "EXEMPTION_CERTIFICATE_NOT_FOUND", "message": "Exemption certificate not found" } } ``` ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}/jurisdictions/bulk_upsert' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "jurisdictions": [ { "country": "US", "state": "CA", "reason": "PURPOSE_RESALE", "identification_type": "STATE_TAX_ID", "identification_number": "12-3456789", "is_active": true }, { "country": "US", "state": "NY", "reason": "ENTITY_TYPE_NON_PROFIT", "identification_type": "FEDERAL_TAX_ID", "identification_number": "98-7654321", "end_date": "2025-12-31", "is_active": true } ] }' ``` ```javascript JavaScript theme={null} const response = await fetch('https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}/jurisdictions/bulk_upsert', { method: 'POST', headers: { 'Authorization': 'Bearer ', 'Content-Type': 'application/json' }, body: JSON.stringify({ jurisdictions: [ { country: 'US', state: 'CA', reason: 'PURPOSE_RESALE', identification_type: 'STATE_TAX_ID', identification_number: '12-3456789', is_active: true }, { country: 'US', state: 'NY', reason: 'ENTITY_TYPE_NON_PROFIT', identification_type: 'FEDERAL_TAX_ID', identification_number: '98-7654321', end_date: '2025-12-31', is_active: true } ] }) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( 'https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}/jurisdictions/bulk_upsert', headers={'Authorization': 'Bearer '}, json={ 'jurisdictions': [ { 'country': 'US', 'state': 'CA', 'reason': 'PURPOSE_RESALE', 'identification_type': 'STATE_TAX_ID', 'identification_number': '12-3456789', 'is_active': True }, { 'country': 'US', 'state': 'NY', 'reason': 'ENTITY_TYPE_NON_PROFIT', 'identification_type': 'FEDERAL_TAX_ID', 'identification_number': '98-7654321', 'end_date': '2025-12-31', 'is_active': True } ] } ) data = response.json() ``` # Delete jurisdiction exemption Source: https://docs.commenda.io/engine/indirect-tax/exemptions/exemption-certificates/jurisdictions-DELETE DELETE /exemption-certificates/{exemption_certificate_id}/jurisdictions/{jurisdiction} Delete a jurisdiction exemption from an exemption certificate Deletes a specific jurisdiction exemption from an exemption certificate. The unique identifier of the exemption certificate. The jurisdiction identifier in the format `{country}_{state}` (e.g., "US\_CA" for California). ```json 204 theme={null} { "message": "Successfully deleted exemption." } ``` ```json 404 theme={null} { "error": { "code": "EXEMPTION_CERTIFICATE_NOT_FOUND", "message": "Exemption certificate not found" } } ``` ```bash cURL theme={null} curl --request DELETE \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}/jurisdictions/US_CA' \ --header 'Authorization: Bearer ' ``` ```javascript JavaScript theme={null} const response = await fetch('https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}/jurisdictions/US_CA', { method: 'DELETE', headers: { 'Authorization': 'Bearer ' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.delete( 'https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}/jurisdictions/US_CA', headers={'Authorization': 'Bearer '} ) data = response.json() ``` # Create jurisdiction exemption Source: https://docs.commenda.io/engine/indirect-tax/exemptions/exemption-certificates/jurisdictions-POST POST /exemption-certificates/{exemption_certificate_id}/jurisdictions Add a new jurisdiction exemption to an exemption certificate Creates a new jurisdiction exemption for an existing exemption certificate. The unique identifier of the exemption certificate. ISO 3166-1 alpha-2 country code. Currently only "US" is supported. ISO 3166-2 subdivision code (e.g., "CA" for California). The reason for the exemption. Valid values: * `PURPOSE_RESALE` * `ENTITY_TYPE_NON_PROFIT` * `GOVERNMENT` * `MANUFACTURER` * `AGRICULTURAL` * `OTHER` The type of identification for the exemption. The identification number for the exemption. The end date of the exemption in ISO 8601 format (YYYY-MM-DD). Whether the exemption is active. Defaults to true. The created jurisdiction exemption. ISO 3166-1 alpha-2 country code. ISO 3166-2 subdivision code. The reason for the exemption. The type of identification. The identification number. Whether the exemption is active. Whether the exemption has expired. The end date of the exemption. Unix timestamp of when the exemption was created. ```json 201 theme={null} { "message": "Successfully created exemption.", "data": { "country": "US", "state": "CA", "reason": "PURPOSE_RESALE", "identification_type": "STATE_TAX_ID", "identification_number": "12-3456789", "is_active": true, "is_expired": false, "end_date": "2025-12-31", "created_at": 1704067200 } } ``` ```json 400 theme={null} { "error": { "code": "DUPLICATE_STATE_FOR_CERTIFICATE", "message": "A jurisdiction exemption already exists for this state" } } ``` ```json 404 theme={null} { "error": { "code": "EXEMPTION_CERTIFICATE_NOT_FOUND", "message": "Exemption certificate not found" } } ``` ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}/jurisdictions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "country": "US", "state": "CA", "reason": "PURPOSE_RESALE", "identification_type": "STATE_TAX_ID", "identification_number": "12-3456789", "end_date": "2025-12-31", "is_active": true }' ``` ```javascript JavaScript theme={null} const response = await fetch('https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}/jurisdictions', { method: 'POST', headers: { 'Authorization': 'Bearer ', 'Content-Type': 'application/json' }, body: JSON.stringify({ country: 'US', state: 'CA', reason: 'PURPOSE_RESALE', identification_type: 'STATE_TAX_ID', identification_number: '12-3456789', end_date: '2025-12-31', is_active: true }) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( 'https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}/jurisdictions', headers={'Authorization': 'Bearer '}, json={ 'country': 'US', 'state': 'CA', 'reason': 'PURPOSE_RESALE', 'identification_type': 'STATE_TAX_ID', 'identification_number': '12-3456789', 'end_date': '2025-12-31', 'is_active': True } ) data = response.json() ``` # Update jurisdiction exemption Source: https://docs.commenda.io/engine/indirect-tax/exemptions/exemption-certificates/jurisdictions-UPDATE POST /exemption-certificates/{exemption_certificate_id}/jurisdictions/{jurisdiction} Update an existing jurisdiction exemption Updates specific fields of a jurisdiction exemption. At least one field must be provided for update. The unique identifier of the exemption certificate. The jurisdiction identifier in the format `{country}_{state}` (e.g., "US\_CA" for California). The reason for the exemption. Valid values: * `PURPOSE_RESALE` * `ENTITY_TYPE_NON_PROFIT` * `GOVERNMENT` * `MANUFACTURER` * `AGRICULTURAL` * `OTHER` The type of identification for the exemption. The identification number for the exemption. The end date of the exemption in ISO 8601 format (YYYY-MM-DD). Whether the exemption is active. ```json 200 theme={null} { "message": "Successfully updated exemption." } ``` ```json 400 theme={null} { "error": { "code": "INVALID_REQUEST_BODY", "message": "At least one field must be provided for update" } } ``` ```json 404 theme={null} { "error": { "code": "EXEMPTION_NOT_FOUND", "message": "Exemption not found for the specified jurisdiction" } } ``` ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}/jurisdictions/US_CA' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "reason": "PURPOSE_RESALE", "is_active": true }' ``` ```javascript JavaScript theme={null} const response = await fetch('https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}/jurisdictions/US_CA', { method: 'POST', headers: { 'Authorization': 'Bearer ', 'Content-Type': 'application/json' }, body: JSON.stringify({ reason: 'PURPOSE_RESALE', is_active: true }) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( 'https://transaction-tax.api.in.commenda.io/api/v1/exemption-certificates/{exemption_certificate_id}/jurisdictions/US_CA', headers={'Authorization': 'Bearer '}, json={ 'reason': 'PURPOSE_RESALE', 'is_active': True } ) data = response.json() ``` # List exemptions by customer Source: https://docs.commenda.io/engine/indirect-tax/exemptions/exemptions-GET GET /exemptions Get all exemptions for a specific customer with filtering options Retrieves a paginated list of all exemptions for a specific customer. Supports filtering by certificate type, jurisdiction, expiration status, and exemption status. The unique identifier of the customer. Cursor for pagination. Use the cursor returned in the previous response to fetch the next page. Number of items to return per page. Must be between 1 and 100. Comma-separated list of certificate types to filter by (e.g., "SINGLE\_STATE,MULTI\_STATE"). Comma-separated list of jurisdictions to filter by in the format `{country}_{state}` (e.g., "US\_CA,US\_NY"). Filter by expiration status. Valid values: * `ACTIVE` - Non-expired exemptions * `EXPIRED` - Expired exemptions Filter by exemption status. Valid values: * `ACTIVE` - Active exemptions * `INACTIVE` - Inactive exemptions Array of exemption objects. The jurisdiction exemption details. ISO 3166-1 alpha-2 country code. ISO 3166-2 subdivision code. The reason for the exemption. The type of identification. The identification number. Whether the exemption is active. Whether the exemption has expired. The end date of the exemption. Unix timestamp of when the exemption was created. The associated exemption certificate details. Unique identifier for the exemption certificate. The customer ID associated with the certificate. The type of exemption certificate. The verification status of the certificate. The exemption certificate number. The effective date of the certificate. Unix timestamp of when the certificate was created. The ID of the associated file. The name of the associated file. Total number of exemptions for the customer. Cursor to use for fetching the next page. Only present if there are more results. ```json 200 theme={null} { "message": "Successfully fetched exemptions.", "data": { "exemptions": [ { "exemption": { "country": "US", "state": "CA", "reason": "PURPOSE_RESALE", "identification_type": "STATE_TAX_ID", "identification_number": "12-3456789", "is_active": true, "is_expired": false, "end_date": "2025-12-31", "created_at": 1704067200, "certificate": { "id": "cert_123abc", "customer_id": "cust_456def", "type": "SINGLE_STATE", "verification_status": "VERIFICATION_SUCCESS", "exemption_certificate_number": "EX-12345", "effective_date": "2024-01-01", "created_at": 1704067200, "file_id": "file_789ghi", "file_name": "exemption_cert.pdf" } } } ], "total_exemptions": 1 } } ``` ```json 400 theme={null} { "error": { "code": "MISSING_REQUIRED_PARAMS", "message": "Missing required parameter: customer_id" } } ``` ```json 404 theme={null} { "error": { "code": "CUSTOMER_NOT_FOUND", "message": "Customer not found" } } ``` ```bash cURL theme={null} curl --request GET \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/exemptions?customer_id=cust_123&limit=20&exemption_jurisdiction=US_CA' \ --header 'Authorization: Bearer ' ``` ```javascript JavaScript theme={null} const response = await fetch('https://transaction-tax.api.in.commenda.io/api/v1/exemptions?customer_id=cust_123&limit=20&exemption_jurisdiction=US_CA', { method: 'GET', headers: { 'Authorization': 'Bearer ' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( 'https://transaction-tax.api.in.commenda.io/api/v1/exemptions', params={ 'customer_id': 'cust_123', 'limit': 20, 'exemption_jurisdiction': 'US_CA' }, headers={'Authorization': 'Bearer '} ) data = response.json() ``` # Files Source: https://docs.commenda.io/engine/indirect-tax/files/files Upload files to Commenda's servers. ## Overview A file object represents a file hosted on Commenda's servers. Currently, files are primarily used to manage exemption certificates, but other use cases are possible as well. ### Linking an exemption certificate 1. Create a file using the `POST /files` endpoint. 2. Save the returned file id. 3. Create or update an exemption certificate with that id in the `file_id` field using `POST /exemption-certificates` or `POST /exemption-certificates/{id}`. # List files Source: https://docs.commenda.io/engine/indirect-tax/files/files-GET GET /files List files for one seller # Create files Source: https://docs.commenda.io/engine/indirect-tax/files/files-POST POST /files Upload a new file to Commenda's server # Delete file Source: https://docs.commenda.io/engine/indirect-tax/files/files-id-DELETE DELETE /files/{id} Deletes a file by its id # Get file Source: https://docs.commenda.io/engine/indirect-tax/files/files-id-GET GET /files/{id} Retrieve one file by its id, along with a signed URL to download it Get a file by id along with a signed URL to download it. More information coming soon. # Filings Source: https://docs.commenda.io/engine/indirect-tax/filings/filings Preview, generate, and manage tax filings for your registered jurisdictions. ## Overview The Filings API lets you preview upcoming tax filings, generate them for a jurisdiction, and manage their lifecycle. Filings represent individual tax returns that your business must submit to a tax authority for a specific period. Each filing includes: * **Tax period** — the date range the filing covers * **Reporting period** — the date range used for reporting (may differ from the tax period) * **Due date** — when the return must be filed * **Frequency** — how often filings occur (monthly, quarterly, annually, etc.) * **Status** — the current state of the filing (`SCHEDULED`, `UPCOMING`, `OVERDUE`, `FILED`, etc.) ## V2 filings V2 filings work with [V2 registrations](/engine/indirect-tax/registrations/v2/registrations-v2) and use `registration_tax_type_id` to identify the jurisdiction and tax type. This replaces the V1 approach of identifying filings by country and state code. V2 filings support: * **International jurisdictions** — EU member states, UK, Canada, and trade bloc schemes (Union OSS, Non-Union OSS, IOSS) * **Composite frequencies** — registrations with multiple filing obligations (e.g., quarterly returns plus annual reconciliation) * **Content-driven calendars** — filing dates and periods are determined by a centralized filing calendar To use V2 filings, you must first create a [V2 registration](/engine/indirect-tax/registrations/v2/registrations-v2-POST) for the jurisdiction. The `registration_tax_type_id` from that registration is used to identify filings. ## Filing workflow Use the [preview endpoint](/engine/indirect-tax/filings/filings-preview-POST) to see what filings would be generated for a registration and time period. This is a read-only operation — no filings are created. Use the [bulk create endpoint](/engine/indirect-tax/filings/filings-bulk-create-POST) to generate the filings. The system creates filing records based on the filing calendar content for your registration. Use the [list endpoint](/engine/indirect-tax/filings/filings-GET-ONE) to view filings and their statuses. Update filings with tax amounts, confirmation numbers, and status changes as you prepare and submit returns. Use the [bulk delete endpoint](/engine/indirect-tax/filings/filings-bulk-delete-DELETE) to remove filings that are no longer needed. Filed returns cannot be deleted. ## Filing response fields V2 filings include additional fields compared to V1: | Field | Description | | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `registration_tax_type_id` | The V2 content ID linking the filing to a registration | | `jurisdiction_name` | Human-readable jurisdiction name (e.g., "California", "Germany") | | `jurisdiction_type` | Type of jurisdiction (e.g., `STATE_OR_PROVINCE`, `COUNTRY`, `TRADEBLOC`) | | `filing_content_id` | Content identifier linking the filing to its calendar entry and contribution box rules. Used together with `registration_tax_type_id` to distinguish parallel filing tracks under the same registration (e.g., a standard return vs. a Dauerfrist extension in Germany). Present for V2 filings with content-driven calendars; null for V1 filings. | | `form_title` | The display name of the filing form | | `description` | Additional description for the filing | | `reporting_period_start_date` | Start of the reporting period | | `reporting_period_end_date` | End of the reporting period | ## Filing contributions For EU and UK filings, Commenda automatically computes the values for each box on the tax return form. These computed values are called **filing contributions**. Contributions are generated during the automated tax breakdown processing cycle for any filing that has content-defined box rules (identified by a `filing_content_id`). The engine: 1. Validates that invoices attached to the filing have the required data (such as ship-from addresses) 2. Aggregates invoice data into buckets grouped by geographic origin/destination, transaction type, tax rate, product type, customer type, and remitter type 3. Evaluates **AGGREGATE** box rules by matching content-defined filters against invoice buckets and summing the appropriate monetary field (taxable amount, tax amount, or gross amount) 4. Evaluates **FORMULA** box rules in sequence, referencing previously computed box values with simple arithmetic ### Supported filing types | Type | Description | | ------------- | ----------------------------------------------------------------------------- | | Country-level | Standard VAT returns for a single jurisdiction (e.g., Germany, France, Italy) | | Union OSS | One-stop shop returns with per-member-state breakdowns for intra-EU B2C sales | | Non-Union OSS | One-stop shop returns for non-EU businesses selling B2C services in the EU | | IOSS | Import one-stop shop returns for low-value goods imported into the EU | Country-level filing contributions are supported for 23 EU member states: Austria, Belgium, Bulgaria, Croatia, Cyprus, Czech Republic, Denmark, Finland, France, Germany, Greece, Hungary, Italy, Latvia, Lithuania, Luxembourg, Malta, Poland, Portugal, Romania, Slovakia, Slovenia, and Spain. Each country includes box rules covering domestic sales at all applicable rate tiers (standard, reduced, super-reduced, and extra-reduced where applicable), domestic purchases, intra-community sales and acquisitions, zero-rated domestic sales, imports, exports, and a formula-based total output VAT box. Sales and returns are automatically netted within each box. For country-level filings, box values are computed once using the filing jurisdiction's rates. For trade-bloc filings (OSS/IOSS), the engine iterates over each destination member state, resolving that state's rates and producing per-jurisdiction contributions. ### Retrieving contributions Use the [`GET /filings/{id}/contributions`](/engine/indirect-tax/filings/filings-contributions-GET) endpoint to retrieve computed contributions for a single filing, or the [`POST /filings/contributions`](/engine/indirect-tax/filings/filings-contributions-batch-POST) batched endpoint to fetch contributions for up to 100 filings in one request. Each contribution includes: | Field | Description | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------ | | `filing_contribution_id` | Content-defined identifier linking the value to its box rule definition | | `box_id` | The tax return box identifier (e.g., `"81"` for German domestic supplies) | | `box_name` | Display name of the box | | `box_order` | Display order on the form | | `box_type` | Classification (e.g., `TAX_BASE`, `TAX_AMOUNT`) | | `value` | Computed amount in minor currency units (e.g., cents) | | `filing_through_jurisdiction` | For OSS/IOSS filings, the Commenda jurisdiction ID of the destination member state. Null for country-level filings | ```json theme={null} // Example: GET /filings/{id}/contributions { "data": { "count": 3, "contributions": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "filing_id": "f1a2b3c4-d5e6-7890-abcd-ef1234567890", "filing_contribution_id": "DE_VAT_01", "filing_through_jurisdiction": null, "value": 150000, "value_type": "INTEGER", "box_id": "81", "box_name": "Supplies and other services", "box_order": 1, "box_type": "TAX_BASE" } ] }, "message": "Successfully fetched filing contributions." } ``` ### Invoice validation During contribution processing, Commenda validates that each invoice has the data required for accurate box computation. Invoices that fail validation are stamped with a per-invoice error code on `tax_breakdown_processing_error_code` and excluded from contribution calculations until the underlying issue is resolved and the next processing cycle runs. | Error code | Meaning | | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `TRANSACTION.ADDRESSES.SHIP_FROM.MISSING` | The invoice has no ship-from address. EU VAT contribution computation needs ship-from to determine intra-EU vs. extra-EU scope. | | `TRANSACTION.CURRENCY.FX_RATE_UNAVAILABLE` | The invoice's `(invoice_currency, transacted_at)` pair cannot be converted to the filing's reporting currency because no FX rate is published for that exact date. | Contributions are idempotent — each processing run replaces all previous contribution values for the filing. This means contributions always reflect the current state of your transaction data. ### Reporting currency and FX conversion EU and UK V2 filings declare a `reporting_currency` on their content filing calendar entry (for example, EUR for German country-level returns, GBP for UK returns). When invoices attached to a filing span multiple currencies, the contribution engine converts each invoice's taxable, tax, and gross amounts from `invoice_currency` into the filing's reporting currency at aggregation time. Conversion uses the invoice's `transacted_at` date to look up the cross-rate. Same-currency invoices short-circuit to a rate of 1.0 — single-currency filings produce values byte-identical to filings computed before FX support was introduced. #### Exact-date matching The engine requires an FX rate published for the exact `transacted_at` date. There is no fallback to the nearest prior date. Filings are authoritative documents, so any gap in the FX rate table for a date that an invoice transacted on must be backfilled before that invoice can be included in a return. When any invoice on a filing cannot be converted, contribution processing fails the entire job: * The filing's contribution sync job is marked `FAILED` with reason `FX_RATE_UNAVAILABLE: N invoice(s) could not be converted to `. * The job's `failure_count` reflects the number of flagged invoices and `success_count` reflects the unaffected remainder. * Each flagged invoice is stamped with `TRANSACTION.CURRENCY.FX_RATE_UNAVAILABLE` on `tax_breakdown_processing_error_code` so the UI can highlight which transactions need attention. * No contribution rows are written. Any previously-correct contributions on the filing are left intact until the FX gap is filled and the sync re-runs. This fail-loud behavior prevents silently submitting a VAT return that omits legitimate revenue. To recover, backfill the missing FX rate and re-trigger contribution sync — the engine clears the per-invoice error codes and re-validates on each run. A filing without a `reporting_currency` populated on its content filing calendar entry fails contribution sync with `MISSING_FILING_CURRENCY`. This is a content configuration gap and must be fixed at the calendar level. #### US and Canadian filings US and Canadian filings are not affected by this conversion path. They use a separate calculation engine that bakes FX into invoice amounts at calc time, targeting USD or CAD respectively. ## Liability report The liability report endpoints provide per-filing snapshots and bulk exports across multiple filings. The two read endpoints return distinct shapes — call them in parallel and merge by `filing_id` when you need both filing-level totals and box-level VAT detail. | Endpoint | Description | | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`POST /filings/liability-report`](/engine/indirect-tax/filings/filings-liability-report-POST) | Returns per-filing liability snapshots. Each entry's `breakdown` object is populated for US and Canadian filings, and `null` for VAT filings. | | [`POST /filings/contributions`](/engine/indirect-tax/filings/filings-contributions-batch-POST) | Returns per-filing tax-return box contributions for up to 100 filings. `contributions` is non-null for VAT filings and `null` for US and Canadian filings. | | [`POST /filings/liability-report/export`](/engine/indirect-tax/filings/filings-liability-report-export-POST) | Queues an asynchronous job that produces one CSV per filing, bundles them into a zip, and emails a signed download link to the recipients you specify. | All three endpoints accept up to 100 filing IDs per request. The export endpoint also requires every filing in the request to belong to the same corporation. Track the export job with the jobs endpoint, filtering by `entity=FILING` and `operation=EXPORT_INDIRECT_TAX_FILINGS_LIABILITY_REPORT`. For multi-filing exports, the worker creates one child job row per filing (with `entity_id` set to the filing UUID) so the per-filing detail page surfaces the export. ## Managed filing When you enable `managed_filing_enabled` on a [V2 registration](/engine/indirect-tax/registrations/v2/registrations-v2-POST), Commenda handles the filing process for that jurisdiction on your behalf. You can toggle this setting when creating or updating a registration. ## API endpoints | Endpoint | Method | Description | | ------------------------------------------------------------------------------------------------------- | ------ | ----------------------------------------------------- | | [`/internal/filings/preview`](/engine/indirect-tax/filings/filings-preview-POST) | POST | Preview proposed filings for a registration | | [`/internal/filings/bulk/create`](/engine/indirect-tax/filings/filings-bulk-create-POST) | POST | Generate filings for a registration | | [`/internal/filings/bulk/delete`](/engine/indirect-tax/filings/filings-bulk-delete-DELETE) | DELETE | Delete filings by registration or filing IDs | | [`/filings/{id}`](/engine/indirect-tax/filings/filings-GET-ONE) | GET | Get a single filing | | [`/filings/{id}/contributions`](/engine/indirect-tax/filings/filings-contributions-GET) | GET | List filing contributions | | [`/filings/contributions`](/engine/indirect-tax/filings/filings-contributions-batch-POST) | POST | Get filing contributions for up to 100 filings | | [`/filings/liability-report`](/engine/indirect-tax/filings/filings-liability-report-POST) | POST | Get per-filing liability snapshots | | [`/filings/liability-report/export`](/engine/indirect-tax/filings/filings-liability-report-export-POST) | POST | Queue an async zipped-CSV export of liability reports | # Get one filing Source: https://docs.commenda.io/engine/indirect-tax/filings/filings-GET-ONE GET /filings/{id} Retrieve one filing by its id # Bulk create filings Source: https://docs.commenda.io/engine/indirect-tax/filings/filings-bulk-create-POST POST https://transaction-tax.api.in.commenda.io/api/v1/internal/filings/bulk/create Generate filings for a registration based on the filing calendar Generate filing records for a registration and time period. The system creates filings based on the filing calendar content, with dates, frequencies, and form titles determined by the registration's content configuration. This endpoint supports two input modes: * **V2** — pass `registration_tax_type_id` to generate filings for a V2 registration * **V1** — pass `country`, `state`, and `filing_frequency` for legacy registrations Use the [preview endpoint](/engine/indirect-tax/filings/filings-preview-POST) first to verify which filings will be created before calling this endpoint. ## Request body The corporation UUID. The V2 registration content ID. When provided, the V2 filing path is used. Example: `"REG_STATE_CEN_06_RST"` The start of the tax period range in `YYYY-MM` format. Example: `"2025-01"` The end of the tax period range in `YYYY-MM` format. If omitted, only filings for the start month are generated. Example: `"2025-12"` ISO country code. Required for V1 filings when `registration_tax_type_id` is not provided. State or province code. Required for V1 filings when `registration_tax_type_id` is not provided. Filing frequency. Required for V1 filings when `registration_tax_type_id` is not provided. ## Behavior * **Duplicate protection** — if a filing already exists for the same registration, filing content, frequency, and due date, it is not recreated. The uniqueness key for V2 filings is the combination of `corporation_id`, `registration_tax_type_id`, `filing_content_id`, `filing_due_date`, and `filing_frequency`. This allows parallel filing tracks under the same registration (e.g., a standard return and a Dauerfrist extension) to coexist. Existing filings that are not in `SCHEDULED` status are preserved. * **Composite frequencies** — if a registration has multiple frequencies (e.g., `QUARTERLY` and `ANNUAL_RECONCILIATION`), filings are generated for all matching calendar entries. * **Ownership validation** — the system verifies that the `registration_tax_type_id` belongs to the specified corporation. ```bash cURL - V2 theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/internal/filings/bulk/create' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "tax_period_start_month": "2025-01", "tax_period_end_month": "2025-12" }' ``` ```json V2 create theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "tax_period_start_month": "2025-01", "tax_period_end_month": "2025-12" } ``` ```json V1 create (legacy) theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "country": "US", "state": "CA", "filing_frequency": "QUARTERLY", "tax_period_start_month": "2025-01", "tax_period_end_month": "2025-12" } ``` ```json 200 theme={null} { "created_filings": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "filing_content_id": "FC_US_06_RST", "jurisdiction_name": "California", "jurisdiction_type": "STATE_OR_PROVINCE", "form_title": "Sales and Use Tax Return", "filing_frequency": "QUARTERLY", "tax_period_start_date": "2025-01-01", "tax_period_end_date": "2025-03-31", "reporting_period_start_date": "2025-01-01", "reporting_period_end_date": "2025-03-31", "filing_due_date": "2025-04-30", "due_date": "2025-04-30", "status": "SCHEDULED", "created_at": 1706700000 } ], "total_created": 4 } ``` ## Related * [Preview filings](/engine/indirect-tax/filings/filings-preview-POST) — Preview before generating * [Bulk delete filings](/engine/indirect-tax/filings/filings-bulk-delete-DELETE) — Remove generated filings * [Filings overview](/engine/indirect-tax/filings/filings) — Filing concepts and lifecycle # Bulk delete filings Source: https://docs.commenda.io/engine/indirect-tax/filings/filings-bulk-delete-DELETE DELETE https://transaction-tax.api.in.commenda.io/api/v1/internal/filings/bulk/delete Delete filings by registration, status filters, or explicit filing IDs Delete filings that are no longer needed. This endpoint supports three input modes: * **By filing IDs** — pass an array of specific filing UUIDs to delete (works on both the legacy and V2 paths) * **V2 filter** — pass `registration_tax_type_id` with `statuses` and optional `due_after` to delete matching filings (requires `?v2=true`) * **V1 filter** — pass `corporation_id` and `state` for legacy filings Filings with status `FILED` cannot be deleted. Include only non-filed statuses in the `statuses` filter. ## Query parameters Set to `true` to use the V2 deletion path. Required when filtering with `registration_tax_type_id`. Optional when deleting by `filing_ids`. ## Request body ### Option 1: delete by filing IDs Array of filing UUIDs to delete. Each value must be a valid UUID. Minimum 1 entry, maximum 100 entries. Example: `["a1b2c3d4-...", "e5f6a7b8-..."]` ### Option 2: V2 filter by registration The V2 registration content ID. Deletes all filings matching the filters for this registration. Requires `?v2=true`. When supplied, `corporation_id` is also required. Required when using `registration_tax_type_id`. Only filings in these statuses are deleted. `FILED` is not allowed. Example: `["SCHEDULED", "UPCOMING"]` Optional date filter. Only filings with a due date after this date are deleted. Format: `YYYY-MM-DD`. Example: `"2025-06-01"` ### Option 3: V1 filter by state The corporation UUID. Required for V1 filter mode. State code. Required for V1 filter mode. ```bash cURL - By filing IDs theme={null} curl --request DELETE \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/internal/filings/bulk/delete' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "filing_ids": [ "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "b2c3d4e5-f6a7-8901-bcde-f12345678901" ] }' ``` ```bash cURL - V2 filter theme={null} curl --request DELETE \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/internal/filings/bulk/delete?v2=true' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "c1d2e3f4-a5b6-7890-abcd-ef1234567890", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "statuses": ["SCHEDULED", "UPCOMING"], "due_after": "2025-06-01" }' ``` ```json By filing IDs theme={null} { "filing_ids": [ "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "b2c3d4e5-f6a7-8901-bcde-f12345678901" ] } ``` ```json V2 filter theme={null} { "corporation_id": "c1d2e3f4-a5b6-7890-abcd-ef1234567890", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "statuses": ["SCHEDULED", "UPCOMING"], "due_after": "2025-06-01" } ``` ```json 200 theme={null} { "deleted_ids": [ "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "b2c3d4e5-f6a7-8901-bcde-f12345678901" ], "total_deleted": 2 } ``` ## Related * [Bulk create filings](/engine/indirect-tax/filings/filings-bulk-create-POST) — Generate filings * [Preview filings](/engine/indirect-tax/filings/filings-preview-POST) — Preview before generating * [Filings overview](/engine/indirect-tax/filings/filings) — Filing concepts and lifecycle # List filing calendar Source: https://docs.commenda.io/engine/indirect-tax/filings/filings-calendar-GET GET https://transaction-tax.api.in.commenda.io/api/v1/filings/calendar Get the filing calendar for a corporation showing all upcoming and past filings Retrieve the filing calendar for a corporation, showing all filings across registrations. Supports cursor-based pagination and an optional V2 mode for enhanced filing data. ## Query parameters The unique identifier (UUID) for the corporation. Number of results per page. Default: `10`, maximum: `100`. Pagination cursor from a previous response. Set to `true` to use V2 filing calendar logic, which includes V2 registration data and content-driven filing calendars. ```bash cURL theme={null} curl --request GET \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/filings/calendar?corporation_id=550e8400-e29b-41d4-a716-446655440000&limit=20&v2=true' \ --header 'Authorization: Bearer ' ``` ```json 200 theme={null} { "message": "Successfully fetched filings.", "data": { "filings": [ { "id": "f1a2b3c4-d5e6-7890-abcd-ef1234567890", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "form_title": "Sales and Use Tax Return", "frequency": "QUARTERLY", "period_start_date": "2024-07-01", "due_date": "2024-10-31", "filing_status": "ACTIVE", "country": "US" } ], "cursor": "eyJpZCI6ImYxYTJiM2M0..." } } ``` # List filing contributions Source: https://docs.commenda.io/engine/indirect-tax/filings/filings-contributions-GET GET /filings/{id}/contributions Retrieve the computed tax box values (contributions) for a specific filing. Each contribution represents a value that maps to a box on a tax return form, such as taxable sales or tax due. Contributions are ordered by box order, then by jurisdiction for multi-jurisdiction filings (e.g., EU OSS/IOSS). # Get filing contributions (batch) Source: https://docs.commenda.io/engine/indirect-tax/filings/filings-contributions-batch-POST POST /filings/contributions Multi-filing analog of `GET /filings/{id}/contributions`. Returns per-filing contribution boxes for a list of filing IDs (max 100). Each entry's `contributions` array is non-null for VAT filings (UK/EU country VAT and OSS/IOSS variants) — possibly empty if the engine has not computed boxes yet — and `null` for US and Canadian filings whose liability lives on the filing row itself. # Get liability report Source: https://docs.commenda.io/engine/indirect-tax/filings/filings-liability-report-POST POST /filings/liability-report Returns per-filing liability snapshots for a list of filing IDs (max 100). Each entry's `breakdown` object is populated for US and Canadian filings, where liability values live on the filing row itself, and `null` for VAT filings (UK and EU country VAT, Union OSS, Non-Union OSS, IOSS) — fetch the box-level VAT detail for those via `POST /filings/contributions`. # Export liability report Source: https://docs.commenda.io/engine/indirect-tax/filings/filings-liability-report-export-POST POST /filings/liability-report/export Queues an asynchronous export job that produces one CSV per filing, bundles them into a zip, uploads the zip to storage, and emails a signed download link to `delivery_recipients` when complete. All filings in a single request must belong to the same corporation (max 100 filings). Poll job status via the jobs endpoint, filtering by `entity=FILING` and `operation=EXPORT_INDIRECT_TAX_FILINGS_LIABILITY_REPORT`. # Preview filings Source: https://docs.commenda.io/engine/indirect-tax/filings/filings-preview-POST POST https://transaction-tax.api.in.commenda.io/api/v1/internal/filings/preview Preview proposed filings for a registration before generating them Preview the filings that would be generated for a given registration and time period. This is a read-only operation — no filings are created. Use this to verify the filing schedule before committing. The preview endpoint supports two input modes: * **V2** — pass `registration_tax_type_id` to preview filings for a V2 registration * **V1** — pass `country`, `state`, and `filing_frequency` for legacy registrations ## Request body The corporation UUID. The V2 registration content ID. When provided, the V2 filing calendar is used. Example: `"REG_STATE_CEN_06_RST"` The start of the tax period range in `YYYY-MM` format. Example: `"2025-01"` The end of the tax period range in `YYYY-MM` format. If omitted, only filings for the start month are returned. Example: `"2025-12"` ISO country code. Required for V1 filings when `registration_tax_type_id` is not provided. State or province code. Required for V1 filings when `registration_tax_type_id` is not provided. Filing frequency. Required for V1 filings when `registration_tax_type_id` is not provided. ## How V2 preview works When you provide a `registration_tax_type_id`, the system: 1. Validates that the registration belongs to the specified corporation 2. Looks up all filing calendar entries for that `registration_tax_type_id` 3. Filters entries to those whose tax period falls within the requested date range 4. Expands composite frequencies — if a registration has multiple frequencies (e.g., `QUARTERLY` and `ANNUAL_RECONCILIATION`), all matching entries are included 5. Returns the proposed filings with dates, frequencies, and form titles ```bash cURL - V2 preview theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/internal/filings/preview' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "tax_period_start_month": "2025-01", "tax_period_end_month": "2025-06" }' ``` ```json V2 preview theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "tax_period_start_month": "2025-01", "tax_period_end_month": "2025-06" } ``` ```json V1 preview (legacy) theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "country": "US", "state": "CA", "filing_frequency": "QUARTERLY", "tax_period_start_month": "2025-01", "tax_period_end_month": "2025-12" } ``` ```json 200 theme={null} { "proposed_filings": [ { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "filing_content_id": "FC_US_06_RST", "jurisdiction_name": "California", "jurisdiction_type": "STATE_OR_PROVINCE", "form_title": "Sales and Use Tax Return", "filing_frequency": "QUARTERLY", "tax_period_start_date": "2025-01-01", "tax_period_end_date": "2025-03-31", "reporting_period_start_date": "2025-01-01", "reporting_period_end_date": "2025-03-31", "filing_due_date": "2025-04-30", "due_date": "2025-04-30", "status": "SCHEDULED" }, { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "filing_content_id": "FC_US_06_RST", "jurisdiction_name": "California", "jurisdiction_type": "STATE_OR_PROVINCE", "form_title": "Sales and Use Tax Return", "filing_frequency": "QUARTERLY", "tax_period_start_date": "2025-04-01", "tax_period_end_date": "2025-06-30", "reporting_period_start_date": "2025-04-01", "reporting_period_end_date": "2025-06-30", "filing_due_date": "2025-07-31", "due_date": "2025-07-31", "status": "SCHEDULED" } ] } ``` ## Related * [Bulk create filings](/engine/indirect-tax/filings/filings-bulk-create-POST) — Generate the previewed filings * [Filings overview](/engine/indirect-tax/filings/filings) — Filing concepts and lifecycle * [V2 registrations](/engine/indirect-tax/registrations/v2/registrations-v2) — Create registrations to enable filings # Introduction Source: https://docs.commenda.io/engine/indirect-tax/introduction Commenda allows your team to manage your entire global indirect tax workflow via API, from registration to tax calculations, filings, and registration threshold tracking. ## API Capabilities **1. Global Indirect Tax Calculation** * Calculate accurate indirect tax rates for each transaction across supported countries (US, GB, and more). **2. Transaction Management** * Create new transactions to track tax liability. * Retrieve transaction details. * Amend existing transactions. * Archive transactions. * Get detailed tax reports including `expected`, `actual` and `adjusted` tax amounts. **3. Registration threshold tracking** * Track your progress toward registration thresholds across US states, Canada, the UK, and the EU. * Evaluate trade bloc rules including EU Union OSS, Non-Union OSS, and IOSS schemes. * Track your historical liabilities across jurisdictions. * File VDAs. **4. Tax Registration Management** * Submit your existing registrations to Commenda. * Request a new state registration. * Retrieve existing registration details. * Update existing registrations. **5. Filing Information** * Get your historical and present compliance calendar. This includes all the state and local filings. * Generate filings and assign them to Commenda. Commenda will then take care of your filings and programmatically keep you updated using Webhook events and jobs. **6. Customer Information** * Create and update customer profiles. * Submit customer exemption certificates. **7. Exemptions** * Create exemption certificates for customers. * Retrieve all exemption certificates. * Update exemption certificates. **8. Files** * CRUD APIs for files managed on Commenda. ## Base URL All API endpoints use the following base URL: ``` https://transaction-tax.api.in.commenda.io/api/v1 ``` All endpoint paths documented in this reference are relative to this base URL. For example, the tax calculation endpoint `POST /calculate` should be called as: ``` POST https://transaction-tax.api.in.commenda.io/api/v1/calculate ``` ## Authentication We implement Bearer token authentication to secure our APIs. This method requires you to include a valid token in the Authorization header of each request. The format is as follows: ```json theme={null} "Authorization": "Bearer " ``` Replace `` with the actual token provided to you by Commenda. Request API keys from the Commenda team for both testing and production. # Locations Source: https://docs.commenda.io/engine/indirect-tax/locations/locations Track where your corporation has physical or legal presence for tax establishment purposes. ## Overview The Locations API lets you manage physical locations for a corporation. Locations are used to determine tax nexus, registration obligations, and establishment presence — particularly for EU trade bloc registrations where physical presence in a member state affects which registration schemes are available. ## Location types | Type | Description | | ------------------------- | --------------------------------------------------- | | `HEADQUARTERS` | Main administrative office | | `BRANCH_OFFICE` | Secondary office location | | `RETAIL_LOCATION` | Customer-facing retail store | | `FACTORY` | Manufacturing facility | | `WAREHOUSE` | Inventory storage or distribution center | | `NATURAL_RESOURCE_SITE` | Natural resource extraction site | | `REGISTERED_OFFICE` | Official legal address on file with authorities | | `REPRESENTATIVE_OFFICE` | Representative office in a foreign jurisdiction | | `CONSTRUCTION_SITE` | Active construction project site | | `THIRD_PARTY_FULFILLMENT` | Third-party fulfillment center | | `REMOTE_EMPLOYEE` | Location where remote employees work | | `DEPENDENT_AGENT` | Agent who acts exclusively on behalf of the company | | `INDEPENDENT_AGENT` | Agent who acts on behalf of multiple companies | | `REGISTRATION` | Location linked to a tax registration | | `OTHER` | Other location type | A single location can have multiple types (e.g., `["HEADQUARTERS", "REGISTERED_OFFICE"]`). ## Establishment rules Locations are checked when creating EU trade bloc registrations: * **Union OSS** requires a qualifying EU establishment (headquarters, branch office, warehouse, factory, retail location, or dependent agent) in the member state country. * **Non-Union OSS** requires that you have no qualifying EU establishment in any EU country. ## API endpoints | Endpoint | Method | Description | | -------------------------------------------------------------------------------- | ------ | -------------------------------- | | [`/locations`](/engine/indirect-tax/locations/locations-POST) | POST | Create a location | | [`/locations`](/engine/indirect-tax/locations/locations-GET) | GET | List locations for a corporation | | [`/locations/{location_id}`](/engine/indirect-tax/locations/locations-id-POST) | POST | Update a location | | [`/locations/{location_id}`](/engine/indirect-tax/locations/locations-id-DELETE) | DELETE | Delete (archive) a location | # List locations Source: https://docs.commenda.io/engine/indirect-tax/locations/locations-GET GET https://transaction-tax.api.in.commenda.io/api/v1/locations List locations for a corporation Retrieve all locations associated with a corporation. Supports cursor-based pagination and optional filtering by jurisdiction. ## Query parameters The unique identifier (UUID) for the corporation. Number of results per page. Default: `10`, maximum: `100`. Pagination cursor from a previous response. Comma-separated list of jurisdiction IDs to filter by. Example: `JUR_US_STATE_CA,JUR_US_STATE_TX` ```bash cURL theme={null} curl --request GET \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/locations?corporation_id=550e8400-e29b-41d4-a716-446655440000&limit=20' \ --header 'Authorization: Bearer ' ``` ```json 200 theme={null} { "message": "Successfully fetched locations.", "data": { "locations": [ { "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "address": { "address_line_1": "123 Main Street", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "location_types": ["HEADQUARTERS", "REGISTERED_OFFICE"], "is_primary": true, "is_active": true, "start_date": "2024-01-01", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" } ], "cursor": "eyJpZCI6ImIyYzNkNGU1..." } } ``` ```json 200 - Empty theme={null} { "message": "Successfully fetched locations.", "data": { "locations": [], "cursor": null } } ``` # Create location Source: https://docs.commenda.io/engine/indirect-tax/locations/locations-POST POST https://transaction-tax.api.in.commenda.io/api/v1/locations Create a location for a corporation Create a location to track where a corporation has physical or legal presence. The address is validated against country-specific requirements. ## Request body The unique identifier (UUID) for the corporation. The location address. Street address. Additional address details. Additional address details. City or locality. State or province code (2-3 characters). Required for countries like US, CA, AU. ZIP or postal code. ISO 3166-1 alpha-2 country code (e.g., `US`, `DE`, `GB`). Array of location types. At least one type is required. Values: `HEADQUARTERS`, `BRANCH_OFFICE`, `RETAIL_LOCATION`, `FACTORY`, `WAREHOUSE`, `NATURAL_RESOURCE_SITE`, `REGISTERED_OFFICE`, `REPRESENTATIVE_OFFICE`, `CONSTRUCTION_SITE`, `THIRD_PARTY_FULFILLMENT`, `REMOTE_EMPLOYEE`, `DEPENDENT_AGENT`, `INDEPENDENT_AGENT`, `REGISTRATION`, `OTHER` Whether this is the primary location for the corporation. ISO date (YYYY-MM-DD) when the location became active. ISO date (YYYY-MM-DD) when the location was closed. Leave empty for active locations. Whether the location is currently active. Defaults to `true`. Optional notes about the location. ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/locations' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "address": { "address_line_1": "123 Main Street", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "location_types": ["HEADQUARTERS", "REGISTERED_OFFICE"], "is_primary": true, "start_date": "2024-01-01" }' ``` ```json Standard theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "address": { "address_line_1": "123 Main Street", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "location_types": ["HEADQUARTERS", "REGISTERED_OFFICE"], "is_primary": true, "start_date": "2024-01-01" } ``` ```json EU warehouse theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "address": { "address_line_1": "Friedrichstraße 100", "city": "Berlin", "postal_code": "10117", "country": "DE" }, "location_types": ["WAREHOUSE"], "start_date": "2024-06-01" } ``` ```json 200 theme={null} { "message": "Successfully created location.", "data": { "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901" } } ``` ```json 400 - Invalid location type theme={null} { "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Failed to validate the request body", "detail": { "description": "invalid location type: INVALID_TYPE" }, "status": 400, "instance": "/api/v1/locations" } } ``` ```json 400 - Missing address fields theme={null} { "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Failed to validate the request body", "detail": { "description": "state is required for country US" }, "status": 400, "instance": "/api/v1/locations" } } ``` # Delete location Source: https://docs.commenda.io/engine/indirect-tax/locations/locations-id-DELETE DELETE https://transaction-tax.api.in.commenda.io/api/v1/locations/{location_id} Archive a location Delete (archive) a location. The location is soft-deleted and will no longer appear in list results. ## Path parameters The unique identifier (UUID) of the location to delete. ```bash cURL theme={null} curl --request DELETE \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/locations/b2c3d4e5-f6a7-8901-bcde-f12345678901' \ --header 'Authorization: Bearer ' ``` ```json 204 theme={null} (No content) ``` ```json 404 - Not found theme={null} { "error": { "type": "LOCATION_NOT_FOUND", "title": "Location not found.", "detail": { "description": "The location does not exist or you don't have access." }, "status": 404, "instance": "/api/v1/locations/b2c3d4e5-f6a7-8901-bcde-f12345678901" } } ``` # Update location Source: https://docs.commenda.io/engine/indirect-tax/locations/locations-id-POST POST https://transaction-tax.api.in.commenda.io/api/v1/locations/{location_id} Update a location's details Update a location's address, types, active status, or date range. ## Path parameters The unique identifier (UUID) of the location to update. ## Request body Updated address. If provided, `country` is required within the address object. Street address. Additional address details. Additional address details. City or locality. State or province code (2-3 characters). ZIP or postal code. ISO 3166-1 alpha-2 country code. Updated array of location types. Minimum 1 type if provided. Whether this is the primary location. Updated start date (YYYY-MM-DD). Updated end date (YYYY-MM-DD). Whether the location is active. Updated notes. ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/locations/b2c3d4e5-f6a7-8901-bcde-f12345678901' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "location_types": ["HEADQUARTERS", "REGISTERED_OFFICE", "WAREHOUSE"], "notes": "Added warehouse function" }' ``` ```json Update types theme={null} { "location_types": ["HEADQUARTERS", "REGISTERED_OFFICE", "WAREHOUSE"], "notes": "Added warehouse function" } ``` ```json Close a location theme={null} { "is_active": false, "end_date": "2025-06-30" } ``` ```json 200 theme={null} { "message": "Successfully updated location.", "data": { "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "address": { "address_line_1": "123 Main Street", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "location_types": ["HEADQUARTERS", "REGISTERED_OFFICE", "WAREHOUSE"], "is_primary": true, "is_active": true, "start_date": "2024-01-01", "notes": "Added warehouse function", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-03-01T09:00:00Z" } } ``` ```json 404 - Not found theme={null} { "error": { "type": "LOCATION_NOT_FOUND", "title": "Location not found.", "detail": { "description": "The location does not exist or you don't have access." }, "status": 404, "instance": "/api/v1/locations/b2c3d4e5-f6a7-8901-bcde-f12345678901" } } ``` # Sync exposure Source: https://docs.commenda.io/engine/indirect-tax/nexus/exposure-sync-POST POST /exposure/sync Trigger an on-demand recompute of registration threshold exposure for a corporation. The exposure engine evaluates the corporation's transactions against jurisdiction-level exposure rules and updates the cached breached set used by `GET /nexus?v2=true`. As part of every successful run, the engine emits an `INDIRECT_TAX.EXPOSURE.COMPUTED` webhook containing the corporation's full current set of exposed jurisdictions (see [Topics and Events](/engine/indirect-tax/webhooks/event)). Use this endpoint when you need fresh exposure data without waiting for the daily background recompute — for example, immediately after ingesting a backfill of historical transactions, or after a registration is created or archived. ## Overview Trigger an on-demand recompute of registration threshold exposure for a corporation. The exposure engine evaluates the corporation's transactions against jurisdiction-level exposure rules and updates the cached breached set returned by [GET /nexus?v2=true](/engine/indirect-tax/nexus/nexus-GET). Every successful run emits an [`INDIRECT_TAX.EXPOSURE.COMPUTED`](/engine/indirect-tax/webhooks/event#indirect-tax-exposure) webhook with the corporation's full current set of exposed jurisdictions. The webhook is only dispatched when at least one subscriber is registered for the topic. ## When to use this endpoint By default, exposure is recomputed automatically — both lazily on read and via a daily background job. Call this endpoint only when you need fresh exposure data immediately, for example: * After ingesting a large backfill of historical transactions and you want exposure (and any downstream consumers listening on the webhook) to reflect the new totals right away. * After creating or archiving a registration, when you want exposure recomputed without waiting for the next scheduled run. * When wiring up a new webhook subscriber and you want to deliver an initial snapshot of the corporation's current exposure. ## Behavior * The full exposure engine runs synchronously. Large corporations may see latency proportional to their transaction volume. * The response returns once the engine has finished and the webhook has been dispatched (or skipped, if no subscribers exist for the topic). * The webhook payload contains the corporation's full current breached set — treat each delivery as a snapshot, not a delta. See [Topics and Events](/engine/indirect-tax/webhooks/event) for the payload shape. * The caller must be authorized to access the corporation; otherwise a `401` is returned. # Get registration thresholds Source: https://docs.commenda.io/engine/indirect-tax/nexus/nexus-GET GET /nexus Get registration threshold exposure for a corporation. By default, returns US-state-level data. Pass `v2=true` to get global jurisdiction-level data covering US, Canada, UK, and EU jurisdictions, including support for multiple exposure rules per jurisdiction (for example, EU Union OSS, Non-Union OSS, and IOSS). # Bulk Products Source: https://docs.commenda.io/engine/indirect-tax/products/bulk-products Upload product metadata in bulk via CSV. ## Overview The Bulk Product Upload endpoint allows sellers to import product data into Commenda using a CSV file. This is especially useful for onboarding existing catalogs or synchronizing product data across platforms. ## Endpoint ``` POST /api/v1/products/bulk_upload/csv ``` ### Request Body ```json theme={null} { "file_id": "string", // Required: ID of the uploaded file "corporation_id": "string", // Optional: Corporation to associate products with "update_protected_columns": boolean // Optional: Whether to update protected columns (source_platform, source_platform_id) } ``` * The `file_id` should point to a previously uploaded CSV file via the `/files` endpoint. * If `corporation_id` is included, additional authorization checks are performed and all products in the CSV must belong to this corporation. * `update_protected_columns` allows updating source platform fields if set to `true`. ### Response Body ```json theme={null} { "data": { "job": { "id": "string", "organization_id": "string", "entity": "PRODUCT", "operation": "IMPORT", "status": "PENDING", "file_name": "string", "source_file_url": "string", "created_at": "timestamp" } }, "message": "Successfully created job for bulk products upload." } ``` The endpoint returns a job object that can be used to track the progress of the bulk upload via the Jobs API. *** ## CSV File Requirements * Must be **CSV format** with headers. * Max file size: **15 MB** * Content-Type must be one of the supported file types (e.g., `text/csv`) * Header row is required. ### CSV Headers | Column Header | Required | Type | Description | | ------------------------- | -------- | ------ | ---------------------------------------------------------------------------- | | `name` | No\* | string | Name of the product. \*Either `name` or `sku` must be provided. | | `description` | No | string | Short description of the product | | `sku` | No\* | string | Unique identifier used by seller. \*Either `name` or `sku` must be provided. | | `product_taxability_code` | No | string | Tax code indicating how the product is taxed. Defaults to `TPP`. | | `source_platform` | No | enum | Integration source (`SHOPIFY`, `STRIPE`, `WOOCOMMERCE`, `BIGCOMMERCE`) | | `source_platform_id` | No | string | Unique product ID from the source platform | | `corporation_id` | Yes | string | UUID of the corporation owning the product | **Important Notes:** * At least one of `name` or `sku` must be provided for each product. * If `name` is provided, it must be at least 3 characters long. * If `source_platform` is provided, `source_platform_id` must also be provided, and vice versa. * If a `corporation_id` is specified in the request body, all products in the CSV must have matching `corporation_id` values. ## Sample CSV ```csv theme={null} name,description,sku,product_taxability_code,source_platform,source_platform_id,corporation_id Sunglasses,UV-protected sunglasses,PT-1035,TPP,SHOPIFY,prod_abc123,acme-corp-uuid Baseball Cap,,CAP-001,TPP,,,acme-corp-uuid ``` *** ## Notes * Commenda creates an async **import job** to process the CSV. * You can monitor job status via the Jobs API. * Only the **first few rows** are validated synchronously. Deeper row-level validation is handled asynchronously in the import job. * The import is **non-blocking**—you’ll receive a job ID to track progress. # Upload bulk products Source: https://docs.commenda.io/engine/indirect-tax/products/bulk-products-POST POST /products/bulk_upload/csv Submit a CSV file of products for processing # Products Source: https://docs.commenda.io/engine/indirect-tax/products/products Manage products and their tax codes for a corporation. Products represent the goods and services your business sells. By creating and maintaining products with appropriate tax codes, you can ensure accurate tax calculations for your transactions. ## Product Ids and SKUs Products can be uniquely identified by either of the following: * `id`: The unique identifier for the product in Commenda's system. * `sku`: A unique identifier generated by the seller and used consistently across each ERP. ## Product Taxability Codes Products can be mapped to [product taxability codes](/engine/indirect-tax/taxcode). Commenda uses product taxability codes to determine whether products are taxable or exempt in each jurisdiction. * Assign product taxability codes to each product with the `POST /product` (create) and `POST /product/:id` (update) endpoints. * When calculating tax for a transaction using the `/calculate` endpoint, provide the `product_id` of the product associated with each line item in order to fetch the associated tax codes from the product itself. ## Bulk Upload of Products Upload product data by sending a POST request to the /products/bulk endpoint. ### Format Files must be uploaded in CSV format, with headers specified in our bulk uploads template. # Delete product Source: https://docs.commenda.io/engine/indirect-tax/products/products-DELETE DELETE /products/:id ```bash cURL theme={null} curl --request DELETE \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/products/123e4567-e89b-12d3-a456-426614174000' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```json 204 Response theme={null} ``` # Get product Source: https://docs.commenda.io/engine/indirect-tax/products/products-GET GET /products ```bash cURL theme={null} curl --request GET \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/products/123e4567-e89b-12d3-a456-426614174000' \ --header 'Authorization: Bearer YOUR_API_KEY' ``` ```json 200 Response theme={null} { "data": { "id": "123e4567-e89b-12d3-a456-426614174000", "name": "Premium Widget", "tax_code": "P0000000", "sku": "WIDGET-001", "description": "A premium quality widget", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "source_platform_id": "shopify-123", "source_platform": "SHOPIFY", "customs_jurisdiction_details": { "US": "8471.30.0100" }, "created_at": 1704067200 }, "message": "Successfully fetched product." } ``` # Create product Source: https://docs.commenda.io/engine/indirect-tax/products/products-POST POST /products Create a new product for a corporation. ```json Request theme={null} { "name": "Premium Widget", "tax_code": "P0000000", "sku": "WIDGET-001", "description": "A premium quality widget", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "customs_jurisdiction_details": { "US": "8471.30.0100" } } ``` ```json 200 Response theme={null} { "data": { "id": "123e4567-e89b-12d3-a456-426614174000", "name": "Premium Widget", "tax_code": "P0000000", "sku": "WIDGET-001", "description": "A premium quality widget", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "source_platform_id": "", "source_platform": "", "customs_jurisdiction_details": { "US": "8471.30.0100" }, "created_at": 1704067200 }, "message": "Successfully created product." } ``` # Update product Source: https://docs.commenda.io/engine/indirect-tax/products/products-POST-ONE POST /products/{id} ```json Request theme={null} { "name": "Updated Premium Widget", "tax_code": "P0000000", "description": "An updated premium quality widget", "weight_in_kg": 2.5, "volume_in_liters": 1.2, "customs_jurisdiction_details": { "US": "8471.30.0100" } } ``` ```json 200 Response theme={null} { "message": "Successfully updated product." } ``` # List Available Jurisdictions Source: https://docs.commenda.io/engine/indirect-tax/registrations/content/available-jurisdictions-POST POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/available-jurisdictions Search for jurisdictions where you can create tax registrations Search for tax jurisdictions where registrations are available. Returns jurisdictions that match your filters, with pagination support for large result sets. ## Request Body Filter criteria for jurisdictions. Filter by ISO 3166-1 alpha-2 country codes. Example: `["US"]` Filter by state or province codes. Example: `["CA", "NY", "TX"]` Filter by jurisdiction type. Values: `TRADEBLOC`, `COUNTRY`, `STATE_OR_PROVINCE`, `CITY`, `COUNTY`, `DISTRICT`, `LOCAL`, `TERRITORY` Filter by available tax types. Values: `RST`, `RUT`, `DTT`, `SST` If `true`, only return jurisdictions that can be registered independently (not covered by another registration). Filter by jurisdictions covered by a specific registration. Useful for finding local jurisdictions under a state registration. Free-text search across jurisdiction names. Example: `"Los Angeles"` or `"California"` Pagination cursor from a previous response. Leave empty for the first page. Maximum number of results to return (1-100). ## Response Fields | Field | Type | Description | | ----------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------- | | `jurisdictions` | array | List of matching jurisdictions | | `jurisdictions[].jurisdiction_id` | string | Unique identifier for the jurisdiction | | `jurisdictions[].jurisdiction_name` | string | Human-readable name | | `jurisdictions[].jurisdiction_type` | string | Type of jurisdiction (`STATE_OR_PROVINCE`, `CITY`, `COUNTY`, `DISTRICT`, `LOCAL`, `COUNTRY`, `TERRITORY`, `TRADEBLOC`) | | `jurisdictions[].state_or_province` | string | State/province code if applicable | | `jurisdictions[].country` | string | ISO country code | | `total` | integer | Total number of matching jurisdictions | | `cursor` | string | Cursor for the next page (empty if no more results) | ```bash cURL - All US States theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/available-jurisdictions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "filters": { "countries": ["US"], "types": ["STATE_OR_PROVINCE"] }, "limit": 50 }' ``` ```bash cURL - Search by Name theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/available-jurisdictions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "search": "Los Angeles", "filters": {"countries": ["US"]}, "limit": 20 }' ``` ```bash cURL - Cities Only theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/available-jurisdictions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "filters": { "countries": ["US"], "states": ["CA"], "types": ["CITY"] }, "limit": 50 }' ``` ```json All US States theme={null} { "filters": { "countries": ["US"], "types": ["STATE_OR_PROVINCE"] }, "limit": 50 } ``` ```json Specific States theme={null} { "filters": { "countries": ["US"], "states": ["CA", "TX", "NY", "FL"] }, "limit": 10 } ``` ```json Search by Name theme={null} { "search": "Los Angeles", "filters": { "countries": ["US"] }, "limit": 20 } ``` ```json Cities in California theme={null} { "filters": { "countries": ["US"], "states": ["CA"], "types": ["CITY"] }, "limit": 50 } ``` ```json Paginated Request theme={null} { "filters": { "countries": ["US"], "types": ["STATE_OR_PROVINCE"] }, "cursor": "SlVSX1VTX1NUQVRFX1dZ", "limit": 10 } ``` ```json 200 theme={null} { "data": { "jurisdictions": [ { "jurisdiction_id": "JUR_US_STATE_CA", "jurisdiction_name": "California", "jurisdiction_type": "STATE_OR_PROVINCE", "state_or_province": "CA", "country": "US" }, { "jurisdiction_id": "JUR_US_STATE_TX", "jurisdiction_name": "Texas", "jurisdiction_type": "STATE_OR_PROVINCE", "state_or_province": "TX", "country": "US" }, { "jurisdiction_id": "JUR_US_STATE_NY", "jurisdiction_name": "New York", "jurisdiction_type": "STATE_OR_PROVINCE", "state_or_province": "NY", "country": "US" } ], "total": 45, "cursor": "SlVSX1VTX1NUQVRFX05Z" } } ``` ```json 400 - Invalid Request theme={null} { "message": "Failed to parse request body.", "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Failed to validate the request body", "detail": "limit must be between 1 and 100", "status": 400, "instance": "/api/v1/registrations/content/available-jurisdictions" } } ``` ## Next Steps After finding jurisdictions, use the [Registration Input Options](/engine/indirect-tax/registrations/content/registration-input-options-POST) endpoint to get the `registration_content_id` and available tax types for each jurisdiction. ## Related * [Registration Content Overview](/engine/indirect-tax/registrations/content/content) — Full content API workflow * [Tax Registrations](/engine/indirect-tax/registrations/registrations) — Registration concepts and lifecycle # Registration Content Source: https://docs.commenda.io/engine/indirect-tax/registrations/content/content Discover available jurisdictions, tax types, and portal requirements for creating registrations ## Overview The Registration Content API provides a data-driven approach to creating tax registrations. Instead of manually specifying jurisdiction details, you use these endpoints to: 1. **Discover jurisdictions** where you can register 2. **Get registration options** (tax types, frequencies) for each jurisdiction 3. **Get portal requirements** (credentials needed for automated filing) This ensures that registrations are created with valid, up-to-date information that matches each jurisdiction's actual requirements. After gathering content information, use the [Create Registration](/engine/indirect-tax/registrations/registrations-POST) endpoint to create your registration. ## Workflow Use [List Available Jurisdictions](/engine/indirect-tax/registrations/content/available-jurisdictions-POST) to find jurisdictions where you can register. Returns `jurisdiction_id` for each matching jurisdiction. ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/available-jurisdictions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{"filters": {"countries": ["US"], "types": ["STATE_OR_PROVINCE"]}}' ``` Use [Get Registration Options](/engine/indirect-tax/registrations/content/registration-input-options-POST) to get the `registration_content_id`, available `tax_types`, and `frequencies` for your selected jurisdictions. ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/registration-input-options' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{"filters": {"jurisdiction_ids": ["JUR_US_STATE_CA"]}}' ``` Use [Get Portal Fields](/engine/indirect-tax/registrations/content/portal-fields-POST) to get the portal credentials needed for automated filing (username, password, PIN, etc.). ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/portal-fields' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{"filters": {"registration_content_ids": ["CCT_US_STATE_CEN_06_RST"]}}' ``` Use [Create Registration](/engine/indirect-tax/registrations/registrations-POST) with the `registration_content_id` from step 2. ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "your-corporation-id", "registration_content_id": "CCT_US_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequency": "QUARTERLY" }' ``` ## Key Concepts ### Jurisdiction IDs Each tax jurisdiction has a unique `jurisdiction_id` like: * `JUR_US_STATE_CA` — California (state) * `JUR_US_COUNTY_CA_LOS_ANGELES` — Los Angeles County * `JUR_US_CITY_CO_DENVER` — Denver (city) ### Registration Content IDs Each registration type has a `registration_content_id` that encodes the jurisdiction and tax type: * `CCT_US_STATE_CEN_06_RST` — California Retail Sales Tax * `CCT_US_STATE_CEN_48_RST` — Texas Retail Sales Tax * `CCT_US_STATE_CEN_36_RST` — New York Retail Sales Tax ### Jurisdiction Types | Type | Description | | ------------------- | ------------------------------------------------------------------------------------------------------ | | `TRADEBLOC` | Trade bloc level (e.g., European Union). Covers multiple member countries under a single registration. | | `COUNTRY` | Country level (for non-US jurisdictions or EU member states) | | `STATE_OR_PROVINCE` | State or province level (most common for US) | | `CITY` | City with separate filing requirements (home-rule) | | `COUNTY` | County with separate filing requirements | | `DISTRICT` | Special taxing district | | `LOCAL` | Other local jurisdiction | | `TERRITORY` | US territory | ### Tax Types | Code | Name | | ----- | -------------------------- | | `RST` | Retail Sales Tax | | `RUT` | Retailer's Use Tax | | `DTT` | District Transaction Tax | | `SST` | Simplified Sellers Use Tax | | `VAT` | Value Added Tax | ## API Endpoints | Endpoint | Description | | -------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | | [`POST /registrations/content/available-jurisdictions`](/engine/indirect-tax/registrations/content/available-jurisdictions-POST) | Search for jurisdictions where you can register | | [`POST /registrations/content/registration-input-options`](/engine/indirect-tax/registrations/content/registration-input-options-POST) | Get tax types and frequencies for jurisdictions | | [`POST /registrations/content/portal-fields`](/engine/indirect-tax/registrations/content/portal-fields-POST) | Get portal credential requirements | ## Related * [Tax Registrations Overview](/engine/indirect-tax/registrations/registrations) — Full registration workflow and concepts * [Create Registration](/engine/indirect-tax/registrations/registrations-POST) — Create a registration using content IDs # Get Portal Fields Source: https://docs.commenda.io/engine/indirect-tax/registrations/content/portal-fields-POST POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/portal-fields Get portal credential requirements for registration content IDs Retrieve the portal information and credential fields required for automated tax filing. Each state has one or more tax portals where credentials are needed to file returns. ## Request Body Array of registration content IDs to get portal fields for. Get these from the [Registration Input Options](/engine/indirect-tax/registrations/content/registration-input-options-POST) endpoint. Example: `["CCT_US_STATE_CEN_06_RST", "CCT_US_STATE_CEN_48_RST"]` ## Response Fields | Field | Type | Description | | --------------------------------- | ------ | ------------------------------------------------- | | `forms` | array | Portal requirements for each registration content | | `forms[].registration_content_id` | string | The registration content ID | | `forms[].jurisdiction_id` | string | The jurisdiction ID | | `forms[].jurisdiction_name` | string | Human-readable jurisdiction name | | `forms[].tax_type` | string | Tax type for this registration | | `forms[].portals` | array | Available portals for this registration | ### Portal Object | Field | Type | Description | | ------------------- | ------ | ------------------------------------------------------ | | `portal_id` | string | Unique identifier for the portal (use in registration) | | `portal_name` | string | Human-readable portal name | | `portal_url` | string | URL to the state's tax portal website | | `credential_fields` | array | Required credential fields | ### Credential Field Object | Field | Type | Description | | ---------------------------- | ------- | ---------------------------------------------- | | `credential_key` | string | Field identifier | | `credential_name` | string | Human-readable field name | | `credential_type` | string | Field type: `text`, `password`, `pin`, etc. | | `required` | boolean | Whether the field is required | | `is_unique_per_registration` | boolean | Whether each registration needs a unique value | | `regex` | string | Validation regex pattern (if applicable) | | `display_order` | integer | Suggested display order for UI | ```bash cURL - Single theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/portal-fields' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "filters": { "registration_content_ids": ["CCT_US_STATE_CEN_06_RST"] } }' ``` ```bash cURL - Multiple theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/portal-fields' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "filters": { "registration_content_ids": ["CCT_US_STATE_CEN_06_RST", "CCT_US_STATE_CEN_48_RST"] } }' ``` ```json Single Registration theme={null} { "filters": { "registration_content_ids": ["CCT_US_STATE_CEN_06_RST"] } } ``` ```json Multiple Registrations theme={null} { "filters": { "registration_content_ids": [ "CCT_US_STATE_CEN_06_RST", "CCT_US_STATE_CEN_48_RST", "CCT_US_STATE_CEN_36_RST" ] } } ``` ```json 200 theme={null} { "data": { "forms": [ { "registration_content_id": "CCT_US_STATE_CEN_06_RST", "jurisdiction_id": "JUR_US_STATE_CA", "jurisdiction_name": "California", "tax_type": "RST", "portals": [ { "portal_id": "PORTAL_CA_CDTFA", "portal_name": "California Department of Tax and Fee Administration", "portal_url": "https://onlineservices.cdtfa.ca.gov/", "credential_fields": [ { "credential_key": "username", "credential_name": "Username", "credential_type": "text", "required": true, "is_unique_per_registration": false, "display_order": 1 }, { "credential_key": "password", "credential_name": "Password", "credential_type": "password", "required": true, "is_unique_per_registration": false, "display_order": 2 }, { "credential_key": "security_question", "credential_name": "Security Question Answer", "credential_type": "text", "required": true, "is_unique_per_registration": false, "display_order": 3 } ] } ] }, { "registration_content_id": "CCT_US_STATE_CEN_48_RST", "jurisdiction_id": "JUR_US_STATE_TX", "jurisdiction_name": "Texas", "tax_type": "RST", "portals": [ { "portal_id": "PORTAL_TX_COMPTROLLER", "portal_name": "Texas Comptroller WebFile", "portal_url": "https://comptroller.texas.gov/taxes/file-pay/", "credential_fields": [ { "credential_key": "taxpayer_number", "credential_name": "Taxpayer Number", "credential_type": "text", "required": true, "is_unique_per_registration": true, "regex": "^[0-9]{11}$", "display_order": 1 }, { "credential_key": "webfile_number", "credential_name": "WebFile Number", "credential_type": "text", "required": true, "is_unique_per_registration": true, "display_order": 2 } ] } ] } ] } } ``` ```json 400 - Missing Content IDs theme={null} { "message": "Invalid request.", "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Missing required field", "detail": "filters.registration_content_ids is required", "status": 400, "instance": "/api/v1/registrations/content/portal-fields" } } ``` ## Using Portal Information ### Storing Credentials Credentials are stored separately from registrations for security. The typical flow: 1. Collect credentials from the user based on `credential_fields` 2. Store credentials securely (via your credentials management system) 3. Reference the stored credentials via `credential_id` when updating the registration ### Multiple Portals Some registrations may have multiple portal options. Present all options to the user and use the selected `portal_id` when creating/updating the registration. ### Credential Reuse When `is_unique_per_registration` is `false`, the same credentials can be used across multiple registrations (common for multi-state sellers using a single account). ## Next Steps With the portal requirements understood, you can: 1. Build UI forms to collect credentials from sellers 2. [Create registrations](/engine/indirect-tax/registrations/registrations-POST) with the `registration_content_id` 3. [Update registrations](/engine/indirect-tax/registrations/registrations-id-POST) to add portal credentials 4. [Request validation](/engine/indirect-tax/registrations/registrations-id-request-validation-POST) to enable automated filing ## Related * [Registration Content Overview](/engine/indirect-tax/registrations/content/content) — Full content API workflow * [Tax Registrations](/engine/indirect-tax/registrations/registrations) — Registration concepts and lifecycle # Get Registration Options Source: https://docs.commenda.io/engine/indirect-tax/registrations/content/registration-input-options-POST POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/registration-input-options Get available tax types, frequencies, and registration content IDs for jurisdictions Retrieve the registration options for one or more jurisdictions. This endpoint returns the `registration_content_id` you'll need to create a registration, along with available tax types and filing frequencies. ## Request Body Array of jurisdiction IDs to get options for. Get these from the [Available Jurisdictions](/engine/indirect-tax/registrations/content/available-jurisdictions-POST) endpoint. Example: `["JUR_US_STATE_CA", "JUR_US_STATE_TX"]` ## Response Fields | Field | Type | Description | | --------------------------------------------------- | ------ | ---------------------------------------------- | | `options` | array | Registration options for each jurisdiction | | `options[].jurisdiction_id` | string | The jurisdiction ID | | `options[].jurisdiction_name` | string | Human-readable name | | `options[].registrations` | array | Available registration types | | `options[].registrations[].registration_content_id` | string | Content ID to use when creating a registration | | `options[].registrations[].tax_type` | string | Primary tax type for this registration | | `options[].registrations[].frequencies` | array | Valid filing frequencies | | `options[].registrations[].related_tax_types` | array | Additional tax types that can/must be included | ### Related Tax Types Some jurisdictions require or allow multiple tax types to be registered together: * `optional: false` — This tax type **must** be included with the primary type * `optional: true` — This tax type **may** be included (your choice) For example, California requires RST + DTT together, while some states allow RST alone. ```bash cURL - Single theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/registration-input-options' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "filters": { "jurisdiction_ids": ["JUR_US_STATE_CA"] } }' ``` ```bash cURL - Multiple theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/registration-input-options' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "filters": { "jurisdiction_ids": ["JUR_US_STATE_CA", "JUR_US_STATE_TX", "JUR_US_STATE_NY"] } }' ``` ```json Single Jurisdiction theme={null} { "filters": { "jurisdiction_ids": ["JUR_US_STATE_CA"] } } ``` ```json Multiple Jurisdictions theme={null} { "filters": { "jurisdiction_ids": ["JUR_US_STATE_CA", "JUR_US_STATE_TX", "JUR_US_STATE_NY"] } } ``` ```json 200 theme={null} { "data": { "options": [ { "jurisdiction_id": "JUR_US_STATE_CA", "jurisdiction_name": "California", "registrations": [ { "registration_content_id": "CCT_US_STATE_CEN_06_RST", "tax_type": "RST", "frequencies": ["MONTHLY", "QUARTERLY", "ANNUAL_CALENDAR_YEAR"], "related_tax_types": [ { "tax_type": "DTT", "optional": false } ] }, { "registration_content_id": "CCT_US_STATE_CEN_06_RUT", "tax_type": "RUT", "frequencies": ["MONTHLY", "QUARTERLY", "ANNUAL_CALENDAR_YEAR"], "related_tax_types": [ { "tax_type": "DTT", "optional": false } ] } ] }, { "jurisdiction_id": "JUR_US_STATE_TX", "jurisdiction_name": "Texas", "registrations": [ { "registration_content_id": "CCT_US_STATE_CEN_48_RST", "tax_type": "RST", "frequencies": ["MONTHLY", "QUARTERLY", "ANNUAL_CALENDAR_YEAR"] } ] } ] } } ``` ```json 400 - Missing Jurisdiction IDs theme={null} { "message": "Invalid request.", "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Missing required field", "detail": "filters.jurisdiction_ids is required", "status": 400, "instance": "/api/v1/registrations/content/registration-input-options" } } ``` ## Using the Response From the response, extract: 1. **`registration_content_id`** — Use this when calling `POST /registrations` 2. **`tax_type`** + **`related_tax_types`** — Combine to form the `tax_types` array 3. **`frequencies`** — Pick one for the `frequency` field ### Example: Creating a California Registration From the response above, California requires RST + DTT: ```json theme={null} { "corporation_id": "your-corporation-id", "registration_content_id": "CCT_US_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequency": "QUARTERLY" } ``` ## Next Steps After getting registration options, use the [Portal Fields](/engine/indirect-tax/registrations/content/portal-fields-POST) endpoint to understand what credentials are needed for automated filing. Then [Create a Registration](/engine/indirect-tax/registrations/registrations-POST) using the `registration_content_id` from this response. ## Related * [List Available Jurisdictions](/engine/indirect-tax/registrations/content/available-jurisdictions-POST) — Find jurisdictions first * [Registration Content Overview](/engine/indirect-tax/registrations/content/content) — Full content API workflow # Tax Registrations Source: https://docs.commenda.io/engine/indirect-tax/registrations/registrations Manage sales tax registrations to enable accurate tax calculations and automated filing. ## Overview A **registration** represents a seller's tax registration with a tax authority in a specific jurisdiction (state, city, county, or district). Commenda tracks these registrations at the corporation level to ensure accurate tax calculations and enable automated filing. Before you can collect and remit sales tax in a jurisdiction, you must be registered with the relevant tax authority. Commenda's registration system: * **Enables accurate tax calculations** — The `/calculate` endpoint uses your active registrations to determine applicable taxes * **Supports automated filing** — Once validated, Commenda automatically files returns on your behalf * **Handles complex jurisdiction hierarchies** — State-level registrations can cover local jurisdictions, or you can register separately for cities/counties with home-rule authority **Getting Started?** See the [Registration Content API](/engine/indirect-tax/registrations/content/content) to discover available jurisdictions and understand what information is needed for each state. ## Key Concepts ### Registration Content Commenda maintains a content database of all available tax jurisdictions and their requirements. Each jurisdiction has a unique `registration_content_id` that you use when creating registrations. Use the [Registration Content API](/engine/indirect-tax/registrations/content/content) to discover jurisdictions and get the required content IDs. This content-based approach ensures: * Correct jurisdiction metadata is automatically applied * Tax type and frequency options are validated against what the jurisdiction actually supports * Portal credentials are collected according to each state's requirements ### Jurisdiction Hierarchy Registrations follow a hierarchy: 1. **Trade bloc registrations** (e.g., EU VAT) — Cover multiple member countries under a single registration. Required before creating member-state-level registrations that reference the trade bloc. 2. **Country registrations** — For countries outside the US, or for EU member states linked to a trade bloc registration. 3. **State/Province registrations** — Required first for US jurisdictions. Cover most tax collection for the state. 4. **Local registrations** (City, County, District) — Optional. Required only for jurisdictions with separate filing requirements (home-rule jurisdictions). **Trade bloc registrations and member states:** * A trade bloc registration (e.g., EU VAT) represents a single registration that covers multiple member countries * When creating a registration for an EU member state, you must link it to your existing trade bloc registration using the `member_state_registration_id` field * The member state registration inherits the portal configuration from the trade bloc registration * Use the [Registration Input Options](/engine/indirect-tax/registrations/content/registration-input-options-POST) endpoint to discover which member state content IDs are available for a trade bloc registration **Local registrations inherit from their parent state:** * When creating a local registration, you must have an active state-level registration first * If you don't provide `tax_types` or `frequency`, they are **automatically inherited** from the parent state * If you do provide them, they must **exactly match** the parent state's values **State updates cascade to local registrations:** * Updating `tax_types` or `frequency` on a state registration **automatically updates all local registrations** under that state * Archiving or closing a state registration **automatically archives/closes all local registrations** under that state ### Tax Types Each registration specifies which tax types you're collecting. Common tax types include: * **RST** — Retail Sales Tax * **RUT** — Retailer's Use Tax * **DTT** — District Transaction Tax * **SST** — Simplified Sellers Use Tax * **VAT** — Value Added Tax (used for UK, EU, and other international jurisdictions) * **GST** — Goods and Services Tax (Canada) * **HST** — Harmonized Sales Tax (Canada) * **PST** — Provincial Sales Tax (Canada) * **QST** — Quebec Sales Tax (Canada) * **BPT** — Business Privilege Tax * **BRT** — Business and Retail Tax Some jurisdictions require multiple tax types to be registered together (e.g., RST + DTT in California). Use the [Registration Input Options](/engine/indirect-tax/registrations/content/registration-input-options-POST) endpoint to discover which tax types are available and required for each jurisdiction. ## Registration Workflow ### Step 1: Discover Available Jurisdictions Use the [Available Jurisdictions](/engine/indirect-tax/registrations/content/available-jurisdictions-POST) endpoint to find jurisdictions where you can register: ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/available-jurisdictions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "filters": { "countries": ["US"], "states": ["CA", "TX", "NY"], "types": ["STATE_OR_PROVINCE"] }, "limit": 50 }' ``` This returns jurisdictions with their `jurisdiction_id` for the next step. ### Step 2: Get Registration Options Use the [Registration Input Options](/engine/indirect-tax/registrations/content/registration-input-options-POST) endpoint to retrieve the available tax types, frequencies, and registration content IDs: ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/registration-input-options' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "filters": { "jurisdiction_ids": ["JUR_US_STATE_CA", "JUR_US_STATE_TX"] } }' ``` Response includes `registration_content_id`, available `tax_types`, `frequencies`, and any related tax types that must be registered together. ### Step 3: Get Portal Credential Requirements Use the [Portal Fields](/engine/indirect-tax/registrations/content/portal-fields-POST) endpoint to understand what credentials are needed for filing: ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/portal-fields' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "filters": { "registration_content_ids": ["CCT_US_STATE_CEN_06_RST"] } }' ``` This returns the portal information and required credential fields (username, password, PIN, etc.) for each state's tax portal. ### Step 4: Create the Registration Use the [Create Registration](/engine/indirect-tax/registrations/registrations-POST) endpoint with the content ID from Step 2: ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_content_id": "CCT_US_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequency": "QUARTERLY", "effective_start_date": "2024-01-01", "tax_registration_id": "123-456789" }' ``` At this point, Commenda will begin returning non-zero tax rates for this jurisdiction from the `/calculate` endpoint. ### Step 5: Add Portal Credentials Use the [Update Registration](/engine/indirect-tax/registrations/registrations-id-POST) endpoint to add portal credentials required for automated filing: ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "portal_id": "PORTAL_CA_CDTFA", "credential_id": "cred_abc123" }' ``` Credentials are stored securely and managed separately from registrations. The `credential_id` references a stored credential set for the specified portal. ### Step 6: Request Validation Use the [Request Validation](/engine/indirect-tax/registrations/registrations-id-request-validation-POST) endpoint to begin automated filing: ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7/request-validation' \ --header 'Authorization: Bearer ' ``` Commenda will: 1. Verify your tax registration ID with the state 2. Test your portal credentials 3. Configure the account for automated filing Monitor the `validation_status` field to track progress. ### Step 7: Automated Filing Begins Once `validation_status` is `VALID`, Commenda will automatically: * Calculate your tax liability at the end of each filing period * File returns with the tax authority * Remit payments on your behalf You should be: * Collecting sales tax using values from the `/calculate` endpoint * Recording completed transactions using the `/transactions` endpoint ## EU trade bloc registrations For businesses selling into the European Union, Commenda supports trade bloc registrations that model the EU as a supra-national jurisdiction covering multiple member states. ### How it works 1. **Create a trade bloc registration** — Register at the EU level using a `TRADEBLOC` jurisdiction type content ID (e.g., for EU VAT). This represents your central EU VAT registration. 2. **Link member state registrations** — When you register in individual EU member states (e.g., Germany, France), pass `member_state_registration_id` referencing your trade bloc registration. This links the member state to the parent EU registration. 3. **Portal inheritance** — Member state registrations automatically inherit the portal configuration from the trade bloc registration. You do not need to specify a `portal_id` separately. ### Example: registering for EU VAT ```bash theme={null} # Step 1: Find the EU trade bloc jurisdiction curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/available-jurisdictions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "filters": { "types": ["TRADEBLOC"] } }' ``` ```bash theme={null} # Step 2: Get registration options for the EU jurisdiction curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/content/registration-input-options' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "filters": { "jurisdiction_ids": ["TRADEBLOC_EU_3000"] } }' ``` ```bash theme={null} # Step 3: Create the trade bloc registration curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_content_id": "", "tax_types": ["VAT"], "frequency": "QUARTERLY" }' ``` ```bash theme={null} # Step 4: Create a member state registration linked to the trade bloc curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_content_id": "", "tax_types": ["VAT"], "frequency": "QUARTERLY", "member_state_registration_id": "" }' ``` The `member_state_registration_id` must reference an active, non-archived trade bloc registration that belongs to the same corporation. The content system validates that the member state content ID is allowed for the given trade bloc registration. ## Registration Lifecycle ### Status Fields | Field | Description | Values | | --------------------- | ----------------------------------------------- | ------------------------------------------------------- | | `validation_status` | Whether Commenda has verified your registration | `PENDING`, `VALIDATION_IN_PROGRESS`, `VALID`, `INVALID` | | `registration_status` | Current stage of the registration | `REGISTRATION_IN_PROGRESS`, `REGISTERED` | ### Validation Status Flow * **PENDING** — Default status. Commenda has your registration info but validation hasn't been requested. * **VALIDATION\_IN\_PROGRESS** — You've called `/request-validation`. Commenda is verifying credentials. * **VALID** — All information verified. Automated filing is ready. * **INVALID** — Issues found. Check the registration for error details and update accordingly. ### Closing a Registration When you stop selling in a jurisdiction, use the [Close Registration](/engine/indirect-tax/registrations/registrations-id-close-POST) endpoint to set an end date: ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7/close' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "effective_end_date": "2024-12-31" }' ``` Closed registrations: * **Still calculate tax** for transactions within the `effective_start_date` to `effective_end_date` range * **Stop calculating tax** for transactions after the `effective_end_date` * Are preserved for historical records and filing obligations ### Archiving a Registration Use the [Archive Registration](/engine/indirect-tax/registrations/registrations-id-archive-POST) endpoint to completely disable a registration: ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7/archive' \ --header 'Authorization: Bearer ' ``` Archived registrations: * Are excluded from list results unless `include_archived: true` is specified * **Do not calculate tax** — archived registrations are completely excluded from tax calculations ### Deleting a Registration Use the [Delete Registration](/engine/indirect-tax/registrations/registrations-id-DELETE) endpoint to permanently remove a registration. Only registrations in `PENDING`, `VALIDATION_IN_PROGRESS`, or `INVALID` status can be deleted: ```bash theme={null} curl --request DELETE \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7' \ --header 'Authorization: Bearer ' ``` Registrations with `validation_status: VALID` cannot be deleted via API. Contact Commenda support for assistance. ## Impact on Tax Calculations The `/calculate` endpoint uses your active registrations to determine applicable taxes: * **No registration** → Tax amount is zero for that jurisdiction * **Archived registration** → Tax amount is zero (not used in calculations) * **Closed registration** → Tax calculated only for transactions within the effective date range * **Active registration** → Correct tax rates applied ## Sample Registration Object ```json theme={null} { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_content_id": "CCT_US_STATE_CEN_06_RST", "jurisdiction_id": "JUR_US_STATE_CA", "jurisdiction_type": "STATE_OR_PROVINCE", "jurisdiction_name": "California", "country": "US", "state_or_province": "CA", "tax_types": ["RST", "DTT"], "frequency": "QUARTERLY", "effective_start_date": "2024-01-01", "tax_registration_id": "123-456789", "member_state_registration_id": null, "portal_id": "PORTAL_CA_CDTFA", "credential_id": "cred_abc123", "registration_status": "REGISTERED", "validation_status": "VALID", "registration_type": "EXISTING", "registered_by": "API", "email_alias": "tax-ca@acme.commenda.io", "created_at": "2024-01-15T10:30:00Z" } ``` The `member_state_registration_id` field is only populated for registrations linked to a trade bloc registration (e.g., EU member state registrations). For US state registrations, this field is `null`. ## API Endpoints ### Registration Content (Discovery) | Endpoint | Method | Description | | --------------------------------------------------------------------------------------------------------------------------------- | ------ | --------------------------------------------- | | [`/registrations/content/available-jurisdictions`](/engine/indirect-tax/registrations/content/available-jurisdictions-POST) | POST | Discover jurisdictions where you can register | | [`/registrations/content/registration-input-options`](/engine/indirect-tax/registrations/content/registration-input-options-POST) | POST | Get tax types, frequencies for jurisdictions | | [`/registrations/content/portal-fields`](/engine/indirect-tax/registrations/content/portal-fields-POST) | POST | Get portal credential requirements | ### Registration Management | Endpoint | Method | Description | | ----------------------------------------------------------------------------------- | ------ | ------------------------------- | | [`/registrations`](/engine/indirect-tax/registrations/registrations-POST) | POST | Create a new registration | | [`/registrations/list`](/engine/indirect-tax/registrations/registrations-GET) | POST | List registrations with filters | | [`/registrations/{id}`](/engine/indirect-tax/registrations/registrations-id-GET) | GET | Get a single registration | | [`/registrations/{id}`](/engine/indirect-tax/registrations/registrations-id-POST) | POST | Update a registration | | [`/registrations/{id}`](/engine/indirect-tax/registrations/registrations-id-DELETE) | DELETE | Delete a registration | ### Registration Lifecycle | Endpoint | Method | Description | | ----------------------------------------------------------------------------------------------------------------------- | ------ | ------------------------------------------- | | [`/registrations/{id}/request-validation`](/engine/indirect-tax/registrations/registrations-id-request-validation-POST) | POST | Request Commenda validation | | [`/registrations/{id}/archive`](/engine/indirect-tax/registrations/registrations-id-archive-POST) | POST | Archive a registration (stops calculations) | | [`/registrations/{id}/close`](/engine/indirect-tax/registrations/registrations-id-close-POST) | POST | Close a registration (sets end date) | # List Registrations Source: https://docs.commenda.io/engine/indirect-tax/registrations/registrations-GET POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/list Retrieve all registrations for a corporation with optional filters List all registrations for a corporation. Supports filtering by country, state, jurisdiction type, registration type, and validation status. This endpoint uses POST (not GET) to support complex filtering via the request body. ## Request Body The unique identifier for the corporation whose registrations you want to retrieve. Filter by ISO 3166-1 alpha-2 country codes. Example: `["US", "CA"]` Filter by state or province codes. Example: `["CA", "NY", "TX"]` Filter by jurisdiction type. Values: `STATE_OR_PROVINCE`, `CITY`, `COUNTY`, `DISTRICT`, `LOCAL`, `COUNTRY`, `TERRITORY`, `TRADEBLOC` Search by jurisdiction name (partial match). Example: `"California"` or `"Los Angeles"` Filter by how the registration was created. Values: * `EXISTING` — Registration created by the user for an existing tax account * `NEW` — Registration created by Commenda for a new tax account Filter by validation status. Values: `PENDING`, `VALIDATION_IN_PROGRESS`, `VALID`, `INVALID` Whether to include archived registrations in the results. ```bash cURL - All theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/list' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000" }' ``` ```bash cURL - By State theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/list' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "countries": ["US"], "states_or_provinces": ["CA", "NY", "TX"] }' ``` ```bash cURL - Local Only theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/list' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "jurisdiction_types": ["CITY", "COUNTY", "DISTRICT"] }' ``` ```bash cURL - Include Archived theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/list' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "include_archived": true }' ``` ```json All theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000" } ``` ```json By State theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "countries": ["US"], "states_or_provinces": ["CA", "NY", "TX"] } ``` ```json By Status theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "validation_status": "PENDING" } ``` ```json By Jurisdiction Type theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "jurisdiction_types": ["CITY", "COUNTY", "DISTRICT"] } ``` ```json By Name theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "jurisdiction_name": "Los Angeles" } ``` ```json Include Archived theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "include_archived": true } ``` ```json 200 theme={null} { "message": "Successfully listed registrations.", "data": { "registrations": [ { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_content_id": "CCT_US_STATE_CEN_06_RST", "jurisdiction_id": "JUR_US_STATE_CA", "jurisdiction_type": "STATE_OR_PROVINCE", "jurisdiction_name": "California", "country": "US", "state_or_province": "CA", "tax_types": ["RST", "DTT"], "frequency": "QUARTERLY", "effective_start_date": "2024-01-15", "tax_registration_id": "123-456789", "portal_id": "PORTAL_CA_CDTFA", "credential_id": "cred_abc123", "registration_status": "REGISTERED", "validation_status": "VALID", "registration_type": "EXISTING", "registered_by": "API", "email_alias": "tax-ca@acme.commenda.io", "created_at": "2024-01-15T10:30:00Z" }, { "id": "8d9f7780-8536-51ef-a55c-c2851cbface8", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_content_id": "CCT_US_STATE_CEN_48_RST", "jurisdiction_id": "JUR_US_STATE_TX", "jurisdiction_type": "STATE_OR_PROVINCE", "jurisdiction_name": "Texas", "country": "US", "state_or_province": "TX", "tax_types": ["RST"], "frequency": "MONTHLY", "effective_start_date": "2024-02-01", "registration_status": "REGISTERED", "validation_status": "PENDING", "registration_type": "EXISTING", "registered_by": "API", "created_at": "2024-02-01T14:20:00Z" } ] } } ``` ```json 400 - Missing Corporation ID theme={null} { "message": "Failed to parse request body.", "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Failed to validate the request body", "detail": "corporation_id is required", "status": 400, "instance": "/api/v1/registrations/list" } } ``` ```json 404 - Corporation Not Found theme={null} { "error": { "type": "CORPORATION_NOT_FOUND", "title": "Corporation not found.", "detail": "The corporation_id '550e8400-e29b-41d4-a716-446655440000' does not exist or you don't have access.", "status": 404, "instance": "/api/v1/registrations/list" } } ``` ## Related * [Get Registration](/engine/indirect-tax/registrations/registrations-id-GET) — Get details for a specific registration * [Create Registration](/engine/indirect-tax/registrations/registrations-POST) — Create a new registration * [Tax Registrations Overview](/engine/indirect-tax/registrations/registrations) — Registration concepts and lifecycle # Create Registration Source: https://docs.commenda.io/engine/indirect-tax/registrations/registrations-POST POST https://transaction-tax.api.in.commenda.io/api/v1/registrations Create a new tax registration for a corporation in a specific jurisdiction Create a registration to enable tax calculations and automated filing for a jurisdiction. Before calling this endpoint, use the [content endpoints](/engine/indirect-tax/registrations/content/content) to discover available jurisdictions and get the required `registration_content_id`. ## Request Body The unique identifier for the corporation. Must be a valid UUID. The content ID identifying the jurisdiction and tax type combination. Obtain this from the `/registrations/content/registration-input-options` endpoint. Example: `CCT_US_STATE_CEN_06_RST` (California Retail Sales Tax) Array of tax types to register for. Must be valid for the selected `registration_content_id`. Common values: * `RST` — Retail Sales Tax * `RUT` — Retailer's Use Tax * `DTT` — District Transaction Tax * `SST` — Simplified Sellers Use Tax **For state registrations:** Required. Check `related_tax_types` from the registration options endpoint for required combinations. **For local registrations:** Optional. If not provided, inherited from parent state. If provided, must exactly match the parent state's tax types. Filing frequency for this registration. Values: `MONTHLY`, `QUARTERLY`, `SEMI_ANNUALLY`, `ANNUAL_CALENDAR_YEAR`, `FISCAL_YEAR`, `QUARTERLY_PREPAY_MONTHLY`, `MONTHLY_ACCELERATED_PREPAY_EARLY` **For state registrations:** Can be set later before validation. **For local registrations:** Optional. If not provided, inherited from parent state. If provided, must exactly match the parent state's frequency. ISO date (YYYY-MM-DD) when the registration became or becomes effective. Optional for new registrations where the date isn't yet known. Your state-issued tax registration ID, permit number, or account number. Required for validation but can be added later via update. The ID of an existing trade bloc registration to link this registration to. Required when creating a registration for an EU member state or any jurisdiction that belongs to a trade bloc. The referenced registration must: * Belong to the same corporation * Be active (not archived or closed) * Have a `registration_content_id` that is listed as an allowed member state for the target content When provided, the portal configuration is automatically inherited from the trade bloc registration. Reference to stored portal credentials. Can be added later via update before requesting validation. The portal ID for the state's tax filing portal. Must be a valid portal for the selected registration content. Get available portals from the `/registrations/content/portal-fields` endpoint. For member state registrations linked to a trade bloc, the portal is inherited automatically and does not need to be specified. ## Workflow 1. **Get the registration\_content\_id** — Use `/registrations/content/available-jurisdictions` to find jurisdictions, then `/registrations/content/registration-input-options` to get content IDs and valid tax types. 2. **Create the registration** — Call this endpoint with required fields. At minimum: `corporation_id`, `registration_content_id`, and `tax_types`. 3. **Complete the registration** — Use `POST /registrations/{id}` to add `tax_registration_id`, `credential_id`, and other fields. 4. **Request validation** — Once complete, call `POST /registrations/{id}/request-validation` to begin automated filing. ## Validation Rules * **Tax types**: Must be valid for the jurisdiction. Invalid combinations return `REGISTRATION_INVALID_TAX_TYPE`. * **Frequency**: Must be one of the frequencies allowed for the jurisdiction. * **Portal ID**: If provided, must be a valid portal for the registration content. * **Duplicate prevention**: Only one registration per jurisdiction per corporation is allowed. ### Trade bloc registration rules When creating a registration that requires a member state link: | Requirement | Details | | ------------------------------------ | --------------------------------------------------------------------------------------------------------- | | **Trade bloc registration required** | The `member_state_registration_id` must reference an existing registration | | **Same corporation** | The trade bloc registration must belong to the same corporation | | **Active registration** | The trade bloc registration must not be archived or closed | | **Allowed content ID** | The trade bloc registration's content ID must be listed as an allowed member state for the target content | ### Local registration rules When creating a local registration (CITY, COUNTY, DISTRICT, etc.): | Requirement | Details | | ----------------------------- | ----------------------------------------------------------------------------------- | | **Parent state required** | Must have an active state-level registration first | | **Parent must be configured** | Parent state must have `tax_types` and `frequency` set | | **Inheritance** | If you omit `tax_types` or `frequency`, they are inherited from the parent state | | **Matching** | If you provide `tax_types` or `frequency`, they must exactly match the parent state | ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_content_id": "CCT_US_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequency": "QUARTERLY", "effective_start_date": "2024-01-15" }' ``` ```json Minimal theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_content_id": "CCT_US_STATE_CEN_48_RST", "tax_types": ["RST"] } ``` ```json Basic theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_content_id": "CCT_US_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequency": "QUARTERLY", "effective_start_date": "2024-01-15" } ``` ```json Complete theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_content_id": "CCT_US_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequency": "QUARTERLY", "effective_start_date": "2024-01-15", "tax_registration_id": "123-456789-00", "portal_id": "PORTAL_CA_CDTFA", "credential_id": "cred_abc123def456" } ``` ```json EU Member State theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_content_id": "", "tax_types": ["VAT"], "frequency": "QUARTERLY", "effective_start_date": "2024-01-01", "member_state_registration_id": "8a1b2c3d-4e5f-6789-abcd-ef0123456789" } ``` ```json 201 theme={null} { "message": "Successfully created registration.", "data": { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_content_id": "CCT_US_STATE_CEN_06_RST", "jurisdiction_id": "JUR_US_STATE_CA", "jurisdiction_type": "STATE_OR_PROVINCE", "jurisdiction_name": "California", "country": "US", "state_or_province": "CA", "tax_types": ["RST", "DTT"], "frequency": "QUARTERLY", "effective_start_date": "2024-01-15", "registration_status": "REGISTERED", "validation_status": "PENDING", "registration_type": "EXISTING", "registered_by": "API", "email_alias": "tax-ca@acme.commenda.io", "created_at": "2024-01-15T10:30:00Z" } } ``` ```json 400 - Invalid Request Body theme={null} { "message": "Failed to parse request body.", "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Failed to validate the request body", "detail": "corporation_id is required; registration_content_id is required", "status": 400, "instance": "/api/v1/registrations" } } ``` ```json 400 - Content Not Found theme={null} { "error": { "type": "REGISTRATION_CONTENT_NOT_FOUND", "title": "Registration content not found.", "detail": "The registration_content_id 'INVALID_ID' does not exist.", "status": 400, "instance": "/api/v1/registrations" } } ``` ```json 400 - Duplicate Registration theme={null} { "error": { "type": "DUPLICATE_REGISTRATIONS_FOUND", "title": "A registration already exists for this jurisdiction.", "detail": "You already have an active registration in California. Update the existing registration instead.", "status": 400, "instance": "/api/v1/registrations" } } ``` ```json 400 - Invalid Tax Type theme={null} { "error": { "type": "REGISTRATION_INVALID_TAX_TYPE", "title": "Invalid tax type for this jurisdiction.", "detail": "Tax type 'XYZ' is not valid for California. Valid options: RST, RUT, DTT.", "status": 400, "instance": "/api/v1/registrations" } } ``` ```json 400 - Parent Registration Required theme={null} { "error": { "type": "REGISTRATION_PARENT_REQUIRED", "title": "State-level registration required.", "detail": "You must have an active California state registration before registering for Los Angeles County.", "status": 400, "instance": "/api/v1/registrations" } } ``` ```json 400 - Parent Missing Tax Types theme={null} { "error": { "type": "REGISTRATION_PARENT_NOT_CONFIGURED", "title": "Parent state registration not configured.", "detail": "The parent state registration does not have tax_types configured. Please configure the state registration first.", "status": 400, "instance": "/api/v1/registrations" } } ``` ```json 400 - Parent Missing Frequency theme={null} { "error": { "type": "REGISTRATION_PARENT_NOT_CONFIGURED", "title": "Parent state registration not configured.", "detail": "The parent state registration does not have frequency configured. Please configure the state registration first.", "status": 400, "instance": "/api/v1/registrations" } } ``` ```json 400 - Frequency Mismatch with Parent theme={null} { "error": { "type": "FREQUENCY_MISMATCH_WITH_PARENT", "title": "Frequency must match parent state.", "detail": "Frequency 'MONTHLY' does not match the parent state registration frequency 'QUARTERLY'.", "status": 400, "instance": "/api/v1/registrations" } } ``` ```json 400 - Tax Type Not in Parent theme={null} { "error": { "type": "TAX_TYPE_MISMATCH_WITH_PARENT", "title": "Tax type not registered at state level.", "detail": "Tax type 'RUT' is not registered at the state level. State tax types: [RST, DTT].", "status": 400, "instance": "/api/v1/registrations" } } ``` ```json 400 - Missing Required Tax Type from Parent theme={null} { "error": { "type": "TAX_TYPE_MISMATCH_WITH_PARENT", "title": "Missing required tax type from state.", "detail": "Tax type 'DTT' from the state registration must be included.", "status": 400, "instance": "/api/v1/registrations" } } ``` ```json 400 - Invalid Effective Date Format theme={null} { "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Invalid effective_start_date format.", "detail": "Date must be in ISO format (YYYY-MM-DD).", "status": 400, "instance": "/api/v1/registrations" } } ``` ```json 400 - Member State Registration Required theme={null} { "error": { "type": "MEMBER_STATE_REGISTRATION_REQUIRED", "title": "Member state registration required.", "detail": "A member state registration is required for this registration content.", "status": 400, "instance": "/api/v1/registrations" } } ``` ```json 400 - Invalid Member State Registration theme={null} { "error": { "type": "INVALID_MEMBER_STATE_REGISTRATION", "title": "Invalid member state registration.", "detail": "The selected member state registration is not allowed for this registration content.", "status": 400, "instance": "/api/v1/registrations" } } ``` ```json 400 - Member State Not Allowed theme={null} { "error": { "type": "MEMBER_STATE_REGISTRATION_NOT_ALLOWED", "title": "Member state registration not accepted.", "detail": "This registration content does not accept a member state registration.", "status": 400, "instance": "/api/v1/registrations" } } ``` ## Related * [Registration Content API](/engine/indirect-tax/registrations/content/content) — Discover jurisdictions and get content IDs * [Update Registration](/engine/indirect-tax/registrations/registrations-id-POST) — Add credentials before validation * [Request Validation](/engine/indirect-tax/registrations/registrations-id-request-validation-POST) — Enable automated filing * [Tax Registrations Overview](/engine/indirect-tax/registrations/registrations) — Full workflow # Delete Registration Source: https://docs.commenda.io/engine/indirect-tax/registrations/registrations-id-DELETE DELETE https://transaction-tax.api.in.commenda.io/api/v1/registrations/{registration_id} Permanently delete a registration Permanently delete a registration. This action cannot be undone. Registrations with `validation_status: VALID` cannot be deleted via API. If you need to remove a validated registration, please contact [Commenda support](mailto:support@commenda.io). ## Path Parameters The unique identifier (UUID) of the registration to delete. ## When to Use Delete vs. Close vs. Archive | Action | Use Case | Effect | | ------------------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------- | | **Delete** | Remove a duplicate, test, or erroneous registration | Permanently removes the registration | | [**Close**](/engine/indirect-tax/registrations/registrations-id-close-POST) | Stop selling in a jurisdiction | Sets end date, keeps for historical records | | [**Archive**](/engine/indirect-tax/registrations/registrations-id-archive-POST) | Completely disable | Stops all calculations, hidden from list | ## Deletable Registrations A registration can only be deleted when `validation_status` is one of: * `PENDING` — Default status, validation not yet requested * `VALIDATION_IN_PROGRESS` — Validation underway but not complete * `INVALID` — Validation failed ## Non-Deletable Registrations Registrations with `validation_status: VALID` cannot be deleted because: 1. Filing history may be associated with the registration 2. Tax calculations reference the registration 3. Compliance records must be preserved For these cases, use the [Close endpoint](/engine/indirect-tax/registrations/registrations-id-close-POST) instead. ```bash theme={null} curl --request DELETE \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7' \ --header 'Authorization: Bearer ' ``` ```json 204 theme={null} No content - Registration successfully deleted ``` ```json 400 - Cannot Delete Valid Registration theme={null} { "error": { "type": "SERVER_INTERNAL_ERROR", "title": "Failed to delete registration.", "detail": "registration with validation_status of VALID cannot be deleted through api; please contact Commenda team", "status": 500, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` ```json 400 - Missing Parameter theme={null} { "error": { "type": "CLIENT_MISSING_PARAMS", "title": "Missing required parameter.", "status": 400, "instance": "/api/v1/registrations/{registration_id}" } } ``` ```json 404 - Not Found theme={null} { "error": { "type": "REGISTRATION_NOT_FOUND", "title": "Registration not found.", "status": 404, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` ## Related * [Close Registration](/engine/indirect-tax/registrations/registrations-id-close-POST) — End on a specific date * [Archive Registration](/engine/indirect-tax/registrations/registrations-id-archive-POST) — Completely disable * [Tax Registrations Overview](/engine/indirect-tax/registrations/registrations) — Registration lifecycle # Get Registration Source: https://docs.commenda.io/engine/indirect-tax/registrations/registrations-id-GET GET https://transaction-tax.api.in.commenda.io/api/v1/registrations/{registration_id} Retrieve details of a specific registration by ID Retrieve the full details of a registration, including its current status, jurisdiction information, and configuration. ## Path Parameters The unique identifier (UUID) of the registration to retrieve. ## Response Fields | Field | Type | Description | | ------------------------- | ------ | ----------------------------------------------------------------------------------------------------- | | `id` | string | Unique identifier for the registration | | `corporation_id` | string | The corporation this registration belongs to | | `registration_content_id` | string | Content ID identifying the jurisdiction and tax type | | `jurisdiction_id` | string | Unique identifier for the jurisdiction | | `jurisdiction_type` | string | Type: `STATE_OR_PROVINCE`, `CITY`, `COUNTY`, `DISTRICT`, `LOCAL`, `COUNTRY`, `TERRITORY`, `TRADEBLOC` | | `jurisdiction_name` | string | Human-readable name of the jurisdiction | | `country` | string | ISO 3166-1 alpha-2 country code | | `state_or_province` | string | State or province code (e.g., "CA", "TX") | | `tax_types` | array | Tax types registered for (e.g., `["RST", "DTT"]`) | | `frequency` | string | Filing frequency | | `effective_start_date` | string | When the registration became effective (YYYY-MM-DD) | | `effective_end_date` | string | When the registration ended (YYYY-MM-DD), if closed | | `tax_registration_id` | string | State-issued tax ID or permit number | | `portal_id` | string | Tax portal identifier | | `credential_id` | string | Reference to stored portal credentials | | `registration_status` | string | `REGISTRATION_IN_PROGRESS` or `REGISTERED` | | `validation_status` | string | `PENDING`, `VALIDATION_IN_PROGRESS`, `VALID`, or `INVALID` | | `registration_type` | string | `EXISTING` or `NEW` | | `registered_by` | string | Who created the registration: `API`, `USER`, `COMMENDA` | | `email_alias` | string | Email alias for tax correspondence | | `archived_at` | string | Timestamp if archived, otherwise null | | `created_at` | string | When the registration was created | | `updated_at` | string | When the registration was last updated | ```bash theme={null} curl --request GET \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7' \ --header 'Authorization: Bearer ' ``` ```json 200 theme={null} { "message": "Successfully fetched registration.", "data": { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_content_id": "CCT_US_STATE_CEN_06_RST", "jurisdiction_id": "JUR_US_STATE_CA", "jurisdiction_type": "STATE_OR_PROVINCE", "jurisdiction_name": "California", "country": "US", "state_or_province": "CA", "tax_types": ["RST", "DTT"], "frequency": "QUARTERLY", "effective_start_date": "2024-01-15", "tax_registration_id": "123-456789", "portal_id": "PORTAL_CA_CDTFA", "credential_id": "cred_abc123", "registration_status": "REGISTERED", "validation_status": "VALID", "registration_type": "EXISTING", "registered_by": "API", "email_alias": "tax-ca@acme.commenda.io", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-20T15:45:00Z" } } ``` ```json 400 - Missing Parameter theme={null} { "error": { "type": "CLIENT_MISSING_PARAMS", "title": "Missing required parameter.", "status": 400, "instance": "/api/v1/registrations/{registration_id}" } } ``` ```json 404 - Not Found theme={null} { "error": { "type": "REGISTRATION_NOT_FOUND", "title": "Registration not found.", "detail": "The registration '7c9e6679-7425-40de-944b-e07fc1f90ae7' does not exist or you don't have access.", "status": 404, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` ## Related * [List Registrations](/engine/indirect-tax/registrations/registrations-GET) — Get all registrations with filters * [Update Registration](/engine/indirect-tax/registrations/registrations-id-POST) — Modify this registration * [Request Validation](/engine/indirect-tax/registrations/registrations-id-request-validation-POST) — Begin automated filing # Update Registration Source: https://docs.commenda.io/engine/indirect-tax/registrations/registrations-id-POST POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/{registration_id} Update an existing registration's details Update a registration to add or modify tax types, frequency, credentials, and other configuration. Use this endpoint to complete a registration before [requesting validation](/engine/indirect-tax/registrations/registrations-id-request-validation-POST). To find valid portal IDs for your registration, use the [Portal Fields](/engine/indirect-tax/registrations/content/portal-fields-POST) endpoint. **Cascade behavior:** When updating `tax_types` or `frequency` on a **state registration**, the changes automatically cascade to all local registrations (cities, counties, districts) under that state. ## Path Parameters The unique identifier (UUID) of the registration to update. ## Request Body All fields are optional. Only the fields you provide will be updated; other fields remain unchanged. Array of tax types to register for. Must be valid for the registration's jurisdiction. Values: `RST`, `RUT`, `DTT`, `SST`, etc. For local jurisdictions (cities, counties), tax types must match the parent state registration. Filing frequency for this registration. Values: `MONTHLY`, `QUARTERLY`, `SEMI_ANNUALLY`, `ANNUAL_CALENDAR_YEAR`, `FISCAL_YEAR`, `QUARTERLY_PREPAY_MONTHLY`, `MONTHLY_ACCELERATED_PREPAY_EARLY` ISO date (YYYY-MM-DD) when the registration became or becomes effective. Your state-issued tax registration ID, permit number, or account number. Reference to stored portal credentials for automated filing. The portal ID for the state's tax filing portal. Must be a valid portal for the registration's content. ## Common Workflows ### Adding Credentials Before Validation After creating a registration, add the credentials needed for automated filing: ```json theme={null} { "tax_registration_id": "123-456789-00", "portal_id": "PORTAL_CA_CDTFA", "credential_id": "cred_abc123def456" } ``` ### Changing Filing Frequency Update the frequency before the next filing period: ```json theme={null} { "frequency": "MONTHLY" } ``` ### Updating Tax Types Switch between valid tax type combinations: ```json theme={null} { "tax_types": ["RUT", "DTT"] } ``` ## Validation Rules * **Tax types**: Must be valid for the jurisdiction. You can switch between valid combinations (e.g., RST+DTT to RUT+DTT). * **Frequency**: Must be one of the frequencies allowed for the jurisdiction. * **Portal ID**: Must be a valid portal for the registration's content. * **Date format**: `effective_start_date` must be in YYYY-MM-DD format. ### State vs. Local Update Behavior | Registration Type | `tax_types` / `frequency` Update | Effect | | ----------------- | ------------------------------------ | -------------------------------------------------------- | | **State** | Allowed | **Cascades to all local registrations** under this state | | **Local** | Allowed only if matches parent state | Updates only the local registration | If you need to change tax types or frequency for local registrations, update the parent state registration instead—the change will automatically cascade to all locals. ```bash cURL - Add Credentials theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "tax_registration_id": "123-456789-00", "portal_id": "PORTAL_CA_CDTFA", "credential_id": "cred_abc123def456" }' ``` ```bash cURL - Change Frequency theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{"frequency": "MONTHLY"}' ``` ```json Add Credentials theme={null} { "tax_registration_id": "123-456789-00", "portal_id": "PORTAL_CA_CDTFA", "credential_id": "cred_abc123def456" } ``` ```json Change Frequency theme={null} { "frequency": "MONTHLY" } ``` ```json Update Multiple Fields theme={null} { "tax_types": ["RST", "DTT"], "frequency": "QUARTERLY", "effective_start_date": "2024-02-01", "tax_registration_id": "123-456789-NEW" } ``` ```json 200 theme={null} { "message": "Successfully updated registration." } ``` ```json 400 - Invalid Tax Type theme={null} { "error": { "type": "REGISTRATION_INVALID_TAX_TYPE", "title": "Invalid tax type for this jurisdiction.", "detail": "Tax type 'XYZ' is not valid for California. Valid options: RST, RUT, DTT.", "status": 400, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` ```json 400 - Invalid Frequency theme={null} { "error": { "type": "REGISTRATION_INVALID_FREQUENCY", "title": "Invalid frequency for this jurisdiction.", "detail": "Frequency 'WEEKLY' is not valid for California. Valid options: MONTHLY, QUARTERLY, ANNUAL_CALENDAR_YEAR.", "status": 400, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` ```json 400 - Invalid Portal ID theme={null} { "error": { "type": "REGISTRATION_INVALID_PORTAL_ID", "title": "Invalid portal for this registration.", "detail": "Portal 'INVALID_PORTAL' is not valid for this registration content.", "status": 400, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` ```json 400 - Tax Type Mismatch with Parent theme={null} { "error": { "type": "TAX_TYPE_MISMATCH_WITH_PARENT", "title": "Tax types must match parent state registration.", "detail": "Local registration tax types [RUT, DTT] do not match parent California state registration tax types [RST, DTT].", "status": 400, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` ```json 400 - Frequency Mismatch with Parent theme={null} { "error": { "type": "FREQUENCY_MISMATCH_WITH_PARENT", "title": "Frequency must match parent state.", "detail": "Frequency 'MONTHLY' does not match the parent state registration frequency 'QUARTERLY'.", "status": 400, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` ```json 400 - Tax Type Not in Parent theme={null} { "error": { "type": "TAX_TYPE_MISMATCH_WITH_PARENT", "title": "Tax type not registered at state level.", "detail": "Tax type 'RUT' is not registered at the state level. State tax types: [RST, DTT].", "status": 400, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` ```json 400 - Missing Required Tax Type from Parent theme={null} { "error": { "type": "TAX_TYPE_MISMATCH_WITH_PARENT", "title": "Missing required tax type from state.", "detail": "Tax type 'DTT' from the state registration must be included.", "status": 400, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` ```json 400 - Invalid Date Format theme={null} { "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Invalid effective_start_date format.", "detail": "Date must be in ISO format (YYYY-MM-DD).", "status": 400, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` ```json 404 - Not Found theme={null} { "error": { "type": "REGISTRATION_NOT_FOUND", "title": "Registration not found.", "status": 404, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` # Archive Registration Source: https://docs.commenda.io/engine/indirect-tax/registrations/registrations-id-archive-POST POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/{registration_id}/archive Archive a registration to stop tax calculations and hide from views Archive a registration to completely exclude it from tax calculations and hide it from default list views. Archived registrations are preserved for historical records but no longer participate in tax processing. ## Path Parameters The unique identifier (UUID) of the registration to archive. ## What Happens When You Archive * **Tax calculations stop** — The registration is no longer considered when calculating taxes for transactions * **Hidden from views** — Excluded from list results unless you set `include_archived: true` * **Data preserved** — All historical data remains intact for reference and auditing ### Cascade Behavior | Registration Type | Effect | | ---------------------- | ----------------------------------------------------------------------------------------- | | **State registration** | Archives the state **and all local registrations** (cities, counties, districts) under it | | **Local registration** | Archives only the local registration (no cascade) | Archiving a state registration will automatically archive all local registrations under that state. This is a bulk operation that cannot be partially undone. ## When to Archive Use archive when you want to: * **Completely disable a registration** — Stop all tax calculations without deleting historical data * **Remove duplicates** — Archive an erroneously created duplicate * **Clean up test data** — Hide test registrations while preserving them for reference ## Archive vs. Close vs. Delete | Action | Use Case | Tax Calculations | Reversible | | ----------- | ------------------------------- | ------------------------------------------- | --------------------- | | **Archive** | Completely disable | **Stopped entirely** | Yes (contact support) | | **Close** | Stop selling on a specific date | Active within date range (start → end date) | No | | **Delete** | Remove entirely | N/A - data removed | No | If you need to stop collecting tax starting from a specific date but preserve calculations for the historical period, use [Close](/engine/indirect-tax/registrations/registrations-id-close-POST) instead. Close keeps the registration active for transactions within the effective date range. ## Viewing Archived Registrations To include archived registrations in list results, set `include_archived: true`: ```json theme={null} POST /registrations/list { "corporation_id": "your-corp-id", "include_archived": true } ``` Archived registrations will have a non-null `archived_at` timestamp. ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7/archive' \ --header 'Authorization: Bearer ' ``` ```json 200 theme={null} { "message": "Successfully archived registration." } ``` ```json 404 - Not Found theme={null} { "error": { "type": "REGISTRATION_NOT_FOUND", "title": "Registration not found.", "status": 404, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7/archive" } } ``` ```json 500 - Archive Failed theme={null} { "error": { "type": "SERVER_INTERNAL_ERROR", "title": "Failed to archive registration.", "status": 500, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7/archive" } } ``` ## Related * [Close Registration](/engine/indirect-tax/registrations/registrations-id-close-POST) — Stop on a specific date (preserves historical calculations) * [Delete Registration](/engine/indirect-tax/registrations/registrations-id-DELETE) — Permanently remove * [List Registrations](/engine/indirect-tax/registrations/registrations-GET) — Use `include_archived: true` to see archived registrations # Close Registration Source: https://docs.commenda.io/engine/indirect-tax/registrations/registrations-id-close-POST POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/{registration_id}/close Close a registration by setting an effective end date Close a registration when you stop doing business in a jurisdiction. This sets an `effective_end_date` and stops tax calculations and filings for transactions after that date. ## Path Parameters The unique identifier (UUID) of the registration to close. ## Request Body ISO date (YYYY-MM-DD) when the registration ends. Must not be before the `effective_start_date`. Example: `"2024-12-31"` ## When to Close a Registration Close a registration when: * **Leaving a state** — You're no longer selling to customers in that jurisdiction * **Closing a tax account** — You've closed your account with the state * **Business closure** — The corporation is ceasing operations in that jurisdiction ## Effect of Closing After the `effective_end_date`: 1. **Tax calculations** — The `/calculate` endpoint returns zero tax for this jurisdiction 2. **Filing** — No returns are filed for periods after the end date 3. **Historical data** — All transaction and filing history is preserved Closing a registration does **not** affect filings for periods up to and including the end date. Commenda will still file final returns as needed. ### Cascade Behavior | Registration Type | Effect | | ---------------------- | -------------------------------------------------------------------------------------------- | | **State registration** | Closes the state **and all local registrations** under it with the same `effective_end_date` | | **Local registration** | Closes only the local registration (no cascade) | Closing a state registration will automatically close all local registrations under that state with the same end date. This is a bulk operation. ## Close vs. Archive vs. Delete | Action | Use Case | Effect on Calculations | Preserves History | | ------------------------------------------------------------------------------- | ---------------------- | ------------------------------------- | ----------------- | | **Close** | Stop selling on a date | Tax calculated only within date range | Yes | | [**Archive**](/engine/indirect-tax/registrations/registrations-id-archive-POST) | Completely disable | **Stopped entirely** | Yes | | [**Delete**](/engine/indirect-tax/registrations/registrations-id-DELETE) | Remove entirely | Removed immediately | No | ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7/close' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{"effective_end_date": "2024-12-31"}' ``` ```json Request Body theme={null} { "effective_end_date": "2024-12-31" } ``` ```json 200 theme={null} { "message": "Successfully closed registration." } ``` ```json 400 - Invalid End Date theme={null} { "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Invalid effective_end_date.", "detail": "Effective end date (2024-01-01) cannot be before the effective start date (2024-06-01).", "status": 400, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7/close" } } ``` ```json 400 - Invalid Date Format theme={null} { "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Invalid effective_end_date format.", "detail": "Date must be in ISO format (YYYY-MM-DD).", "status": 400, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7/close" } } ``` ```json 404 - Not Found theme={null} { "error": { "type": "REGISTRATION_NOT_FOUND", "title": "Registration not found.", "status": 404, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7/close" } } ``` ## After Closing The registration will show the `effective_end_date` field: ```json theme={null} { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "effective_start_date": "2024-01-01", "effective_end_date": "2024-12-31", "validation_status": "VALID", "...": "..." } ``` If you need to reopen a closed registration, contact [Commenda support](mailto:support@commenda.io). ## Related * [Archive Registration](/engine/indirect-tax/registrations/registrations-id-archive-POST) — Completely disable (stops all calculations) * [Tax Registrations Overview](/engine/indirect-tax/registrations/registrations) — Registration lifecycle # Request Validation Source: https://docs.commenda.io/engine/indirect-tax/registrations/registrations-id-request-validation-POST POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/{registration_id}/request-validation Request Commenda to validate your registration credentials and begin automated filing Request validation of a registration to enable automated tax filing. Once validated, Commenda will automatically file returns and remit payments on your behalf. ## Path Parameters The unique identifier (UUID) of the registration to validate. ## Before Requesting Validation Ensure your registration includes: 1. **Tax registration ID** — Your state-issued permit number or account number 2. **Portal credentials** — `portal_id` and `credential_id` for the state's tax portal 3. **Frequency** — Filing frequency for the jurisdiction 4. **Effective start date** — When the registration became effective Missing any required information will cause validation to fail. Use [Get Registration](/engine/indirect-tax/registrations/registrations-id-GET) to check what's been provided, and [Update Registration](/engine/indirect-tax/registrations/registrations-id-POST) to add missing fields. Need to know what portal credentials are required? Use the [Portal Fields](/engine/indirect-tax/registrations/content/portal-fields-POST) endpoint to get the credential requirements for your registration. ## What Happens During Validation When you call this endpoint, Commenda will: 1. **Verify your tax registration** — Confirm your tax ID is valid with the state 2. **Test portal credentials** — Log into the state's tax portal to verify access 3. **Configure for filing** — Set up the account for automated filing The `validation_status` will change from `PENDING` to `VALIDATION_IN_PROGRESS`. ## Validation Outcomes ### Success: `validation_status: VALID` Your registration is validated and ready for automated filing: * `auto_filing_status` will change to `FILING` * Commenda will file returns at the end of each filing period ### Failure: `validation_status: INVALID` Something went wrong during validation. Common issues: * Invalid tax registration ID * Incorrect portal credentials * Account not configured correctly with the state Check the registration for error details and update the registration to correct the issues, then request validation again. ## Monitoring Validation Progress Poll the registration using [Get Registration](/engine/indirect-tax/registrations/registrations-id-GET) to check status: ```bash theme={null} curl --request GET \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7' \ --header 'Authorization: Bearer ' ``` The `validation_status` field will show: * `VALIDATION_IN_PROGRESS` — Validation is underway * `VALID` — Validation succeeded * `INVALID` — Validation failed (check for error details) ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7/request-validation' \ --header 'Authorization: Bearer ' ``` ```json 200 - Validation Started theme={null} { "message": "Successfully started validation process for your registration." } ``` ```json 200 - Already In Progress theme={null} { "message": "Validation is already in progress." } ``` ```json 404 - Not Found theme={null} { "error": { "type": "REGISTRATION_NOT_FOUND", "title": "Registration not found.", "status": 404, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7/request-validation" } } ``` ```json 500 - Validation Failed to Start theme={null} { "message": "Failed to request validation.", "error": { "type": "SERVER_INTERNAL_ERROR", "title": "Failed to request validation.", "detail": "Unable to initiate validation. Please ensure all required fields are provided.", "status": 500, "instance": "/api/v1/registrations/7c9e6679-7425-40de-944b-e07fc1f90ae7/request-validation" } } ``` ## Next Steps After validation succeeds: 1. **Start collecting tax** — Use the `/calculate` endpoint to get accurate tax amounts 2. **Record transactions** — Submit completed transactions via the `/transactions` endpoint 3. **Monitor filings** — Use the `/filings` endpoints to track filing status 4. **Check for issues** — Subscribe to registration webhooks to be notified of any problems ## Related * [Update Registration](/engine/indirect-tax/registrations/registrations-id-POST) — Add missing fields before validation * [Portal Fields](/engine/indirect-tax/registrations/content/portal-fields-POST) — Get portal credential requirements * [Tax Registrations Overview](/engine/indirect-tax/registrations/registrations) — Full workflow # List Available Jurisdictions Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/content/available-jurisdictions-POST POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/available-jurisdictions Search for jurisdictions where you can create V2 tax registrations Search for tax jurisdictions where V2 registrations are available. Returns jurisdictions that match your filters, with cursor-based pagination for large result sets. ## Request body Filter criteria for jurisdictions. Filter by ISO 3166-1 alpha-2 country codes. Example: `["US", "DE"]` Filter by state or province codes. Example: `["CA", "NY", "TX"]` Filter by jurisdiction type. Values: `TRADEBLOC`, `COUNTRY`, `STATE_OR_PROVINCE`, `CITY`, `COUNTY`, `DISTRICT`, `LOCAL`, `TERRITORY` Free-text search across jurisdiction names. Example: `"California"` or `"Germany"` Pagination cursor from a previous response. Leave empty for the first page. Maximum number of results to return (1–100). ```bash cURL - US states theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/available-jurisdictions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "filters": { "countries": ["US"], "types": ["STATE_OR_PROVINCE"] }, "limit": 50 }' ``` ```bash cURL - Search theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/available-jurisdictions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "search": "Germany", "limit": 10 }' ``` ```json US states theme={null} { "filters": { "countries": ["US"], "types": ["STATE_OR_PROVINCE"] }, "limit": 50 } ``` ```json EU countries theme={null} { "filters": { "types": ["COUNTRY"], "countries": ["DE", "FR", "IT", "ES"] }, "limit": 20 } ``` ```json Trade blocs theme={null} { "filters": { "types": ["TRADEBLOC"] } } ``` ```json 200 theme={null} { "data": { "jurisdictions": [ { "jurisdiction_id": "JUR_US_STATE_CA", "jurisdiction_name": "California", "jurisdiction_type": "STATE_OR_PROVINCE", "country": "US", "state": "CA" }, { "jurisdiction_id": "JUR_US_STATE_TX", "jurisdiction_name": "Texas", "jurisdiction_type": "STATE_OR_PROVINCE", "country": "US", "state": "TX" } ], "total": 45, "cursor": "SlVSX1VTX1NUQVRFX05Z" } } ``` ```json 400 - Invalid request theme={null} { "message": "Failed to parse request body.", "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Failed to validate the request body", "detail": "limit must be between 1 and 100", "status": 400, "instance": "/api/v1/registrations/v2/content/available-jurisdictions" } } ``` ## Related * [Available Registrations](/engine/indirect-tax/registrations/v2/content/available-registrations-POST) — Get registration options for jurisdictions * [V2 Registration Content Overview](/engine/indirect-tax/registrations/v2/content/content-v2) — Full content API workflow # Get Available Registrations Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/content/available-registrations-POST POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/available-registrations Get registration options with tax types, frequencies, and portal IDs for given jurisdictions Retrieve the available registration options for one or more jurisdictions. Returns structured registration data including `registration_tax_type_id`, parsed composite tax types, parsed composite frequencies, and associated portal IDs. ## Request body Array of jurisdiction IDs to get registration options for. Get these from the [Available Jurisdictions](/engine/indirect-tax/registrations/v2/content/available-jurisdictions-POST) endpoint. Minimum 1, maximum 100 items. Example: `["JUR_US_STATE_CA", "JUR_US_STATE_TX"]` ## Response structure Each jurisdiction returns one or more registration objects. Each registration includes: * **`registration_tax_type_id`** — The content ID to use when creating a registration * **`tax_type_options`** — Available tax type combinations with parsed composite structure * **`frequencies`** — Available filing frequency combinations with parsed composite structure * **`portal_ids`** — Portal IDs for credential lookup ### Composite tax types Tax types are returned as structured objects instead of raw strings: ```json theme={null} { "primary": "RST", "related": [ { "value": "DTT", "optional": false } ] } ``` * `optional: false` — This related type **must** be included when creating the registration * `optional: true` — This related type **may** be included at your discretion ### Composite frequencies Frequencies follow the same structure: ```json theme={null} { "primary": "QUARTERLY", "related": [ { "value": "ANNUAL_RECONCILIATION", "optional": false } ] } ``` ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/available-registrations' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "jurisdiction_ids": ["JUR_US_STATE_CA"] }' ``` ```json Single jurisdiction theme={null} { "jurisdiction_ids": ["JUR_US_STATE_CA"] } ``` ```json Multiple jurisdictions theme={null} { "jurisdiction_ids": ["JUR_US_STATE_CA", "JUR_US_STATE_TX", "TRADEBLOC_EU_3000"] } ``` ```json 200 theme={null} { "data": { "registrations": [ { "registration_id": "REG_STATE_CEN_06", "jurisdiction_id": "JUR_US_STATE_CA", "jurisdiction_name": "California", "jurisdiction_type": "STATE_OR_PROVINCE", "registration_name": "Sales and Use Tax", "tax_type_options": [ { "registration_tax_type_id": "REG_STATE_CEN_06_RST", "tax_types": { "primary": "RST", "related": [ { "value": "DTT", "optional": false } ] }, "is_default": true, "effective_start_date": "2024-01-01", "portal_ids": ["PORTAL_CA_CDTFA"], "frequencies": [ { "primary": "MONTHLY", "related": [] }, { "primary": "QUARTERLY", "related": [] }, { "primary": "ANNUAL_CALENDAR_YEAR", "related": [] } ] } ] } ] } } ``` ```json 400 - Missing jurisdiction IDs theme={null} { "message": "Failed to parse request body.", "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Failed to validate the request body", "detail": "jurisdiction_ids is required", "status": 400, "instance": "/api/v1/registrations/v2/content/available-registrations" } } ``` ```json 400 - Too many jurisdiction IDs theme={null} { "message": "Failed to parse request body.", "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Failed to validate the request body", "detail": "jurisdiction_ids must contain at most 100 items", "status": 400, "instance": "/api/v1/registrations/v2/content/available-registrations" } } ``` ## Using the response From the response, extract: 1. **`registration_tax_type_id`** — Use this when calling `POST /registrations/v2` 2. **`tax_types`** — Combine primary and required related types into the `tax_types` array 3. **`frequencies`** — Pick one frequency option and pass all its components in the `frequencies` array 4. **`portal_ids`** — Use with the [Portal Fields](/engine/indirect-tax/registrations/v2/content/portal-fields-POST) endpoint to get credential requirements ### Example: creating a California registration From the response above, California requires RST + DTT (DTT is not optional): ```json theme={null} { "corporation_id": "your-corporation-id", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequencies": ["QUARTERLY"] } ``` ## Related * [Available Jurisdictions](/engine/indirect-tax/registrations/v2/content/available-jurisdictions-POST) — Find jurisdictions first * [Registration Conditions](/engine/indirect-tax/registrations/v2/content/registration-conditions-POST) — Check conditions for trade bloc registrations * [Portal Fields](/engine/indirect-tax/registrations/v2/content/portal-fields-POST) — Get credential requirements # Registration Content V2 Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/content/content-v2 Discover available jurisdictions, registration options, conditions, and portal requirements for V2 registrations ## Overview The V2 Registration Content API provides a data-driven approach to creating tax registrations. Use these endpoints to discover what's available and what's required before creating a registration. The V2 content system adds several capabilities over V1: * **Supported regions** — Discover which regions (US, EU, Canada, UK) are available and get pre-built jurisdiction filters * **Registration conditions** — Query prerequisite, mutual exclusivity, and member country requirements * **Tax type details** — Get descriptions and recommendations for each tax type * **Portal field hints** — Credential fields now include optional `helper_text` for UI display guidance After gathering content information, use the [Create Registration V2](/engine/indirect-tax/registrations/v2/registrations-v2-POST) endpoint to create your registration. ## Workflow Use [Available Jurisdictions](/engine/indirect-tax/registrations/v2/content/available-jurisdictions-POST) to find jurisdictions where you can register. Filter by country, state, or jurisdiction type. ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/available-jurisdictions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{"filters": {"countries": ["US"], "types": ["STATE_OR_PROVINCE"]}}' ``` Use [Available Registrations](/engine/indirect-tax/registrations/v2/content/available-registrations-POST) to get `registration_tax_type_id`, tax type options, and frequency options for your selected jurisdictions. ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/available-registrations' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{"jurisdiction_ids": ["JUR_US_STATE_CA"]}' ``` For trade bloc registrations (EU OSS, IOSS), use [Registration Conditions](/engine/indirect-tax/registrations/v2/content/registration-conditions-POST) to understand prerequisites and conflicts. ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/registration-conditions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{"registration_tax_type_id": "REG_TRADEBLOC_EU_3000_UOSS_VAT"}' ``` Use [Portal Fields](/engine/indirect-tax/registrations/v2/content/portal-fields-POST) to get the credential fields needed for automated filing. ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/portal-fields' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{"portal_ids": ["PORTAL_CA_CDTFA"]}' ``` Use [Create Registration V2](/engine/indirect-tax/registrations/v2/registrations-v2-POST) with the `registration_tax_type_id` from step 2. ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "your-corporation-id", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequencies": ["QUARTERLY"] }' ``` ## API endpoints | Endpoint | Description | | -------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | | [`GET /registrations/v2/content/supported-regions`](/engine/indirect-tax/registrations/v2/content/supported-regions-GET) | Get supported regions and their jurisdiction filters | | [`POST /registrations/v2/content/available-jurisdictions`](/engine/indirect-tax/registrations/v2/content/available-jurisdictions-POST) | Search for jurisdictions where you can register | | [`POST /registrations/v2/content/available-registrations`](/engine/indirect-tax/registrations/v2/content/available-registrations-POST) | Get registration options for jurisdictions | | [`POST /registrations/v2/content/registration-conditions`](/engine/indirect-tax/registrations/v2/content/registration-conditions-POST) | Get conditions for a registration type | | [`POST /registrations/v2/content/portal-fields`](/engine/indirect-tax/registrations/v2/content/portal-fields-POST) | Get portal credential requirements | | [`POST /registrations/v2/content/tax-type-details`](/engine/indirect-tax/registrations/v2/content/tax-type-details-POST) | Get tax type descriptions | ## Related * [Tax Registrations V2 Overview](/engine/indirect-tax/registrations/v2/registrations-v2) — Full V2 registration workflow and concepts * [Create Registration V2](/engine/indirect-tax/registrations/v2/registrations-v2-POST) — Create a registration using V2 content IDs # Get Portal Fields Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/content/portal-fields-POST POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/portal-fields Get portal credential requirements for V2 registrations Retrieve portal information and credential fields required for automated tax filing. Each jurisdiction has one or more tax portals where credentials are needed to file returns. V2 portal fields are looked up by `portal_id` (from the [Available Registrations](/engine/indirect-tax/registrations/v2/content/available-registrations-POST) response), not by `registration_content_id` as in V1. ## Request body Array of portal IDs to get fields for. Get these from the `portal_ids` field in the [Available Registrations](/engine/indirect-tax/registrations/v2/content/available-registrations-POST) response. Minimum 1, maximum 100 items. Example: `["PORTAL_CA_CDTFA", "PORTAL_DE_ELSTER"]` ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/portal-fields' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "portal_ids": ["PORTAL_CA_CDTFA"] }' ``` ```json Single portal theme={null} { "portal_ids": ["PORTAL_CA_CDTFA"] } ``` ```json Multiple portals theme={null} { "portal_ids": ["PORTAL_CA_CDTFA", "PORTAL_TX_COMPTROLLER"] } ``` ```json 200 theme={null} { "data": { "portals": [ { "portal_id": "PORTAL_CA_CDTFA", "portal_name": "California Department of Tax and Fee Administration", "portal_url": "https://onlineservices.cdtfa.ca.gov/", "credential_fields": [ { "credential_key": "username", "credential_name": "Username", "credential_type": "STRING", "required": true, "is_unique_per_registration": false, "helper_text": "Enter the username you use to log in to the CDTFA portal", "display_order": 1 }, { "credential_key": "password", "credential_name": "Password", "credential_type": "STRING", "required": true, "is_unique_per_registration": false, "display_order": 2 } ] } ] } } ``` ```json 400 - Missing portal IDs theme={null} { "message": "Failed to parse request body.", "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Failed to validate the request body", "detail": "portal_ids is required", "status": 400, "instance": "/api/v1/registrations/v2/content/portal-fields" } } ``` ## Credential field properties | Field | Type | Description | | ---------------------------- | ------- | ------------------------------------------------------------------------- | | `credential_key` | string | Field identifier used when storing credentials | | `credential_name` | string | Human-readable label for the field | | `credential_type` | string | Input type (`STRING`, `FILE`, etc.) | | `required` | boolean | Whether the field must be provided | | `helper_text` | string | Optional hint text for UI display, explaining what to enter in this field | | `is_unique_per_registration` | boolean | Whether each registration needs a unique value | | `regex` | string | Validation regex pattern (if applicable) | | `display_order` | integer | Suggested display order for UI rendering | ## Related * [Available Registrations](/engine/indirect-tax/registrations/v2/content/available-registrations-POST) — Get portal IDs for jurisdictions * [Credential Lookup](/engine/indirect-tax/registrations/v2/registrations-v2-credentials-GET) — Check if credentials already exist for a portal * [V2 Registration Content Overview](/engine/indirect-tax/registrations/v2/content/content-v2) — Full content API workflow # Get Registration Conditions Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/content/registration-conditions-POST POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/registration-conditions Get prerequisite, mutual exclusivity, and member country conditions for a registration type Retrieve the conditions that apply to a specific registration tax type. Conditions define relationships between registrations — prerequisites that must be met, conflicts that block creation, and member country choices for trade bloc schemes. Check conditions before creating trade bloc or international registrations to understand what's required and what conflicts exist. ## Request body The registration tax type ID to get conditions for. Get this from the [Available Registrations](/engine/indirect-tax/registrations/v2/content/available-registrations-POST) endpoint. Example: `"REG_TRADEBLOC_EU_3000_UOSS_VAT"` ## Condition types | Type | Description | Create behavior | | ------------------------------------ | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------- | | `PREREQUISITE_REGISTRATION` | At least one of the listed registrations must be active | Blocked if no prerequisite is active | | `MUTUALLY_EXCLUSIVE` | Cannot coexist with any of the listed registrations | Blocked if any listed registration is active | | `MUTUALLY_EXCLUSIVE_WITH_MSI` | Cannot coexist with listed registrations in the selected member state country only | Blocked only in the specific country | | `MEMBER_COUNTRY_TO_REGISTER_THROUGH` | You must choose one of the listed countries to register through | Pass `registered_through_registration_tax_type_id` when creating | ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/registration-conditions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "registration_tax_type_id": "REG_TRADEBLOC_EU_3000_UOSS_VAT" }' ``` ```json Request body theme={null} { "registration_tax_type_id": "REG_TRADEBLOC_EU_3000_UOSS_VAT" } ``` ```json 200 theme={null} { "data": { "conditions": [ { "type": "PREREQUISITE_REGISTRATION", "registration_options": [ { "registration_tax_type_id": "REG_COUNTRY_DE_3001_VAT", "registration_name": "Germany VAT", "jurisdiction_id": "JUR_COUNTRY_DE", "jurisdiction_name": "Germany", "jurisdiction_type": "COUNTRY", "portal_ids": ["PORTAL_DE_ELSTER"] }, { "registration_tax_type_id": "REG_COUNTRY_FR_3002_VAT", "registration_name": "France VAT", "jurisdiction_id": "JUR_COUNTRY_FR", "jurisdiction_name": "France", "jurisdiction_type": "COUNTRY", "portal_ids": ["PORTAL_FR_IMPOTS"] } ] }, { "type": "MUTUALLY_EXCLUSIVE", "registration_options": [ { "registration_tax_type_id": "REG_TRADEBLOC_EU_3000_NUOSS_VAT", "registration_name": "Non-Union OSS", "jurisdiction_id": "TRADEBLOC_EU_3000", "jurisdiction_name": "European Union", "jurisdiction_type": "TRADEBLOC", "portal_ids": [] } ] } ] } } ``` ```json 200 - No conditions theme={null} { "data": { "conditions": [] } } ``` ```json 400 - Missing field theme={null} { "message": "Failed to parse request body.", "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Failed to validate the request body", "detail": "registration_tax_type_id is required", "status": 400, "instance": "/api/v1/registrations/v2/content/registration-conditions" } } ``` ## Using conditions when creating registrations ### Prerequisites If a `PREREQUISITE_REGISTRATION` condition exists, at least one of the listed registrations must be active for your corporation. For Union OSS, this means you need an active domestic VAT registration in an EU member state. When creating, pass the UUID of your existing domestic registration as `member_state_registration_id`: ```json theme={null} { "corporation_id": "your-corp-id", "registration_tax_type_id": "REG_TRADEBLOC_EU_3000_UOSS_VAT", "tax_types": ["VAT"], "frequencies": ["QUARTERLY"], "member_state_registration_id": "" } ``` ### Member country to register through If a `MEMBER_COUNTRY_TO_REGISTER_THROUGH` condition exists (Non-Union OSS, IOSS), you must choose one of the listed countries and pass its content ID: ```json theme={null} { "corporation_id": "your-corp-id", "registration_tax_type_id": "REG_TRADEBLOC_EU_3000_NUOSS_VAT", "tax_types": ["VAT"], "frequencies": ["QUARTERLY"], "registered_through_registration_tax_type_id": "REG_COUNTRY_DE_3001_VAT" } ``` ### Mutual exclusivity If a `MUTUALLY_EXCLUSIVE` condition exists, creating the registration is blocked when any of the listed registrations are active. You must archive or close the conflicting registration first. ## Related * [Available Registrations](/engine/indirect-tax/registrations/v2/content/available-registrations-POST) — Get registration tax type IDs * [Create Registration V2](/engine/indirect-tax/registrations/v2/registrations-v2-POST) — Create a registration with condition fields * [Tax Registrations V2](/engine/indirect-tax/registrations/v2/registrations-v2) — EU trade bloc registration details # Get Supported Regions Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/content/supported-regions-GET GET https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/supported-regions Get the list of supported regions and their jurisdiction filters for tax registrations Retrieve the list of regions supported for tax registration. Each region includes jurisdiction filter sets that you can pass directly to the [Available Jurisdictions](/engine/indirect-tax/registrations/v2/content/available-jurisdictions-POST) endpoint to discover registerable jurisdictions within that region. Use this endpoint to build region-based navigation in your UI or to determine which jurisdiction filters to apply when searching for available registrations. ## Response fields | Field | Type | Description | | ------------------------------------------------ | ------ | ----------------------------------------------------------------------------------- | | `regions` | array | List of supported regions | | `regions[].region_id` | string | Unique identifier for the region (e.g., `US`, `EU`, `CA`, `GB`) | | `regions[].region_name` | string | Human-readable name (e.g., "United States", "European Union") | | `regions[].jurisdiction_filter_sets` | array | One or more filter sets to use when querying available jurisdictions | | `regions[].jurisdiction_filter_sets[].countries` | array | ISO country codes to filter by | | `regions[].jurisdiction_filter_sets[].states` | array | State or province codes to filter by | | `regions[].jurisdiction_filter_sets[].types` | array | Jurisdiction types to filter by (e.g., `STATE_OR_PROVINCE`, `COUNTRY`, `TRADEBLOC`) | ```bash cURL theme={null} curl --request GET \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/supported-regions' \ --header 'Authorization: Bearer ' ``` ```json 200 theme={null} { "data": { "regions": [ { "region_id": "US", "region_name": "United States", "jurisdiction_filter_sets": [ { "countries": ["US"] } ] }, { "region_id": "EU", "region_name": "European Union", "jurisdiction_filter_sets": [ { "types": ["TRADEBLOC"] }, { "countries": ["AT", "BE", "BG", "CY", "CZ", "DE", "DK", "EE", "ES", "FI", "FR", "GR", "HR", "HU", "IE", "IT", "LT", "LU", "LV", "MT", "NL", "PL", "PT", "RO", "SE", "SI", "SK"], "types": ["COUNTRY"] } ] }, { "region_id": "CA", "region_name": "Canada", "jurisdiction_filter_sets": [ { "countries": ["CA"] } ] }, { "region_id": "GB", "region_name": "United Kingdom", "jurisdiction_filter_sets": [ { "countries": ["GB"], "types": ["COUNTRY"] } ] } ] } } ``` ## Using filter sets Each region may return multiple `jurisdiction_filter_sets`. To get all jurisdictions for a region, query the [Available Jurisdictions](/engine/indirect-tax/registrations/v2/content/available-jurisdictions-POST) endpoint once per filter set and combine the results. For example, the EU region returns two filter sets — one for trade bloc-level registrations (Union OSS, Non-Union OSS, IOSS) and another for individual EU member country registrations. ```bash theme={null} # Get EU trade bloc registrations curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/available-jurisdictions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{"filters": {"types": ["TRADEBLOC"]}}' # Get EU member country registrations curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/available-jurisdictions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{"filters": {"countries": ["DE", "FR", "IT"], "types": ["COUNTRY"]}}' ``` ## Related * [Available Jurisdictions](/engine/indirect-tax/registrations/v2/content/available-jurisdictions-POST) — Search for jurisdictions using the filter sets * [Available Registrations](/engine/indirect-tax/registrations/v2/content/available-registrations-POST) — Get registration options for discovered jurisdictions * [V2 Registration Content Overview](/engine/indirect-tax/registrations/v2/content/content-v2) — Full content API workflow # Get Tax Type Details Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/content/tax-type-details-POST POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/tax-type-details Get detailed descriptions of tax types for given jurisdictions Retrieve detailed descriptions and recommendations for tax types available in specific jurisdictions. Use this to help users understand which tax type to select when creating a registration. ## Request body Array of jurisdiction IDs to get tax type details for. Minimum 1, maximum 100 items. Example: `["JUR_US_STATE_CA"]` ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/tax-type-details' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "jurisdiction_ids": ["JUR_US_STATE_CA"] }' ``` ```json Single jurisdiction theme={null} { "jurisdiction_ids": ["JUR_US_STATE_CA"] } ``` ```json Multiple jurisdictions theme={null} { "jurisdiction_ids": ["JUR_US_STATE_CA", "JUR_US_STATE_TX"] } ``` ```json 200 theme={null} { "data": { "tax_type_details": [ { "jurisdiction_id": "JUR_US_STATE_CA", "tax_type": "RST", "official_name": "Retail Sales Tax", "display_name": "Sales Tax", "short_description": "Tax on retail sales of tangible personal property", "full_description": "California imposes a sales tax on retailers for the privilege of selling tangible personal property at retail.", "recommended_for": ["B2C", "SaaS"] } ] } } ``` ```json 400 - Missing jurisdiction IDs theme={null} { "message": "Failed to parse request body.", "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Failed to validate the request body", "detail": "jurisdiction_ids is required", "status": 400, "instance": "/api/v1/registrations/v2/content/tax-type-details" } } ``` ## Response fields | Field | Type | Description | | ------------------- | ------ | -------------------------------------------------------------- | | `jurisdiction_id` | string | The jurisdiction these details apply to | | `tax_type` | string | Tax type code (e.g., `RST`, `VAT`) | | `official_name` | string | Official name of the tax type | | `display_name` | string | Shorter display name | | `short_description` | string | Brief description (may be null) | | `full_description` | string | Detailed description of the tax type | | `recommended_for` | array | Business types this tax type is recommended for (may be empty) | ## Related * [Available Registrations](/engine/indirect-tax/registrations/v2/content/available-registrations-POST) — Get registration options with tax types * [V2 Registration Content Overview](/engine/indirect-tax/registrations/v2/content/content-v2) — Full content API workflow # Tax Registrations V2 Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/registrations-v2 Manage tax registrations with enhanced support for international jurisdictions, composite tax types, and condition-based validation. ## Overview The **V2 Registration API** is the next generation of Commenda's tax registration system. It introduces enhanced support for international jurisdictions (including EU trade bloc schemes), composite tax types and filing frequencies, and automated condition validation for complex registration rules. V2 registrations use a content-driven approach where each registration is identified by a `registration_tax_type_id` — a content ID that encodes the jurisdiction, registration type, and tax type combination. The system validates your inputs against the content database to ensure correctness. **Getting started?** Use the [V2 Content API](/engine/indirect-tax/registrations/v2/content/content-v2) to discover available jurisdictions, registration options, and conditions before creating registrations. ## What's different from V1 | Feature | V1 | V2 | | --------------------------- | ----------------------------- | ---------------------------------------------------------------------- | | **Content identifier** | `registration_content_id` | `registration_tax_type_id` | | **Filing frequency** | Single string (`"QUARTERLY"`) | Array of strings (`["QUARTERLY", "ANNUAL_RECONCILIATION"]`) | | **Condition validation** | Manual | Automated (prerequisites, mutual exclusivity, EU establishment checks) | | **EU trade bloc support** | Basic (member state linking) | Full (Union OSS, Non-Union OSS, IOSS with establishment rules) | | **Registration conditions** | Not exposed | Queryable via dedicated endpoint | | **Tax type details** | Not available | Queryable with descriptions and recommendations | ## Key concepts ### Registration tax type IDs Each registration option has a unique `registration_tax_type_id` that encodes the jurisdiction and tax type combination. Examples: * `REG_STATE_CEN_06_RST` — California Retail Sales Tax * `REG_COUNTRY_DE_3001_VAT` — Germany VAT * `REG_TRADEBLOC_EU_3000_UOSS_VAT` — EU Union One-Stop Shop VAT Use the [Available Registrations](/engine/indirect-tax/registrations/v2/content/available-registrations-POST) endpoint to discover these IDs. ### Composite tax types Some registrations require multiple tax types to be filed together. V2 represents these as structured objects: ```json theme={null} { "primary": "RST", "related": [ { "value": "DTT", "optional": false } ] } ``` * **Primary** — The base tax type (always required) * **Related** with `optional: false` — Must be included alongside the primary type * **Related** with `optional: true` — May be included at your discretion When creating a registration, pass all required tax types in the `tax_types` array. ### Composite filing frequencies Similarly, some jurisdictions require multiple filing frequencies. V2 represents frequencies as arrays: ```json theme={null} { "primary": "QUARTERLY", "related": [ { "value": "ANNUAL_RECONCILIATION", "optional": false } ] } ``` When creating a registration, pass the full set of frequencies in the `frequencies` array (e.g., `["QUARTERLY", "ANNUAL_RECONCILIATION"]`). Available frequency values: `MONTHLY`, `QUARTERLY`, `SEMI_ANNUALLY`, `ANNUAL_CALENDAR_YEAR`, `FISCAL_YEAR`, `MONTHLY_ACCELERATED_PREPAY_EARLY`, `QUARTERLY_PREPAY_MONTHLY`, `ANNUAL_RECONCILIATION`, `BI_MONTHLY`, `TRI_ANNUALLY`, `QUARTERLY_FEB`, `QUARTERLY_MAR` ### Registration conditions V2 introduces queryable conditions that define relationships between registrations: | Condition type | Description | | ------------------------------------ | ----------------------------------------------------------------------------------------------- | | `PREREQUISITE_REGISTRATION` | At least one of the listed registrations must be active before you can create this registration | | `MUTUALLY_EXCLUSIVE` | You cannot hold this registration if any of the listed registrations are active | | `MUTUALLY_EXCLUSIVE_WITH_MSI` | Blocks the registration only in the specific member state country you select | | `MEMBER_COUNTRY_TO_REGISTER_THROUGH` | You must choose a member country to register through (for Non-Union OSS, IOSS) | Use the [Registration Conditions](/engine/indirect-tax/registrations/v2/content/registration-conditions-POST) endpoint to query these before creating a registration. ### Managed filing You can enable Commenda-managed filing on a registration by setting `managed_filing_enabled` to `true` when creating or updating it. When managed filing is enabled, Commenda handles the filing process on your behalf for that jurisdiction. ### Filing management V2 registrations integrate with the [Filings API](/engine/indirect-tax/filings/filings) to let you preview, generate, and manage tax filings. Use your `registration_tax_type_id` to: * **[Preview filings](/engine/indirect-tax/filings/filings-preview-POST)** — see what filings would be generated for a time period * **[Generate filings](/engine/indirect-tax/filings/filings-bulk-create-POST)** — create filing records from the filing calendar * **[Delete filings](/engine/indirect-tax/filings/filings-bulk-delete-DELETE)** — remove filings that are no longer needed Registrations with composite frequencies (e.g., `QUARTERLY` plus `ANNUAL_RECONCILIATION`) automatically generate filings for all applicable frequencies. ### Supported regions Use the [Supported Regions](/engine/indirect-tax/registrations/v2/content/supported-regions-GET) endpoint to retrieve the list of regions available for tax registration (US, EU, Canada, UK). Each region includes jurisdiction filter sets that you can pass directly to the Available Jurisdictions endpoint. ## Registration workflow ### Step 1: Discover available jurisdictions Use the [Supported Regions](/engine/indirect-tax/registrations/v2/content/supported-regions-GET) endpoint to get region-based filter sets, then pass them to the [Available Jurisdictions](/engine/indirect-tax/registrations/v2/content/available-jurisdictions-POST) endpoint to find jurisdictions where you can register: ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/available-jurisdictions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "filters": { "countries": ["US"], "types": ["STATE_OR_PROVINCE"] }, "limit": 50 }' ``` ### Step 2: Get registration options Use the [Available Registrations](/engine/indirect-tax/registrations/v2/content/available-registrations-POST) endpoint to get `registration_tax_type_id`, tax types, and frequencies: ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/available-registrations' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "jurisdiction_ids": ["JUR_US_STATE_CA"] }' ``` ### Step 3: Check conditions (if applicable) For trade bloc or international registrations, check conditions before creating: ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/registration-conditions' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "registration_tax_type_id": "REG_TRADEBLOC_EU_3000_UOSS_VAT" }' ``` ### Step 4: Get portal credential requirements Use the [Portal Fields](/engine/indirect-tax/registrations/v2/content/portal-fields-POST) endpoint to understand what credentials are needed: ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/content/portal-fields' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "portal_ids": ["PORTAL_CA_CDTFA"] }' ``` ### Step 5: Create the registration Use the [Create Registration](/engine/indirect-tax/registrations/v2/registrations-v2-POST) endpoint: ```bash theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequencies": ["QUARTERLY"], "effective_start_date": "2024-01-01" }' ``` ## EU trade bloc registrations V2 provides full support for EU One-Stop Shop (OSS) and Import One-Stop Shop (IOSS) registration schemes with automated establishment validation. ### Supported schemes | Scheme | Registration tax type ID pattern | Requirements | | ----------------- | --------------------------------- | ------------------------------------------------------- | | **Union OSS** | `REG_TRADEBLOC_EU_3000_UOSS_VAT` | Qualifying EU establishment in the member state country | | **Non-Union OSS** | `REG_TRADEBLOC_EU_3000_NUOSS_VAT` | No qualifying EU establishment in any EU country | | **IOSS** | `REG_TRADEBLOC_EU_3000_IOSS_VAT` | For imports of goods valued under €150 | ### Union OSS example ```bash theme={null} # Create a Union OSS registration linked to a German domestic registration curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_TRADEBLOC_EU_3000_UOSS_VAT", "tax_types": ["VAT"], "frequencies": ["QUARTERLY"], "member_state_registration_id": "" }' ``` The `member_state_registration_id` must reference an active domestic registration in an EU country where your business has a qualifying establishment (headquarters, branch office, warehouse, factory, retail location, or dependent agent). ### Non-Union OSS example ```bash theme={null} # Create a Non-Union OSS registration through a member country curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_TRADEBLOC_EU_3000_NUOSS_VAT", "tax_types": ["VAT"], "frequencies": ["QUARTERLY"], "registered_through_registration_tax_type_id": "REG_COUNTRY_DE_3001_VAT" }' ``` Non-Union OSS registration is blocked if your business has any qualifying EU establishment. This is validated automatically when you create the registration. ## Registration lifecycle ### Status fields | Field | Description | Values | | --------------------- | ----------------------------------------------- | ------------------------------- | | `validation_status` | Whether Commenda has verified your registration | `PENDING`, `VALID`, `INVALID` | | `registration_status` | Current stage of the registration | `PENDING`, `ACTIVE`, and others | ### Managing registrations * **[Update](/engine/indirect-tax/registrations/v2/registrations-v2-id-POST)** — Modify tax types, frequencies, credentials, or other fields * **[Close](/engine/indirect-tax/registrations/v2/registrations-v2-id-close-POST)** — Set an effective end date when you stop operating in a jurisdiction * **[Archive](/engine/indirect-tax/registrations/v2/registrations-v2-id-archive-POST)** — Soft-delete a registration (excluded from calculations and default list views) * **[Delete](/engine/indirect-tax/registrations/v2/registrations-v2-id-DELETE)** — Permanently remove a registration (only allowed when `validation_status` is not `VALID`) ## Sample registration object ```json theme={null} { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequencies": ["QUARTERLY"], "jurisdiction_id": "JUR_US_STATE_CA", "jurisdiction_name": "California", "jurisdiction_type": "STATE_OR_PROVINCE", "registration_name": "Sales and Use Tax", "effective_start_date": "2024-01-01", "managed_filing_enabled": false, "registered_by": "COMMENDA", "registration_status": "PENDING", "validation_status": "PENDING", "created_at": "2024-01-15T10:30:00Z" } ``` ## API endpoints ### Registration content (discovery) | Endpoint | Method | Description | | --------------------------------------------------------------------------------------------------------------------------------- | ------ | ---------------------------------------------- | | [`/registrations/v2/content/supported-regions`](/engine/indirect-tax/registrations/v2/content/supported-regions-GET) | GET | Get supported regions and jurisdiction filters | | [`/registrations/v2/content/available-jurisdictions`](/engine/indirect-tax/registrations/v2/content/available-jurisdictions-POST) | POST | Search for available jurisdictions | | [`/registrations/v2/content/available-registrations`](/engine/indirect-tax/registrations/v2/content/available-registrations-POST) | POST | Get registration options for jurisdictions | | [`/registrations/v2/content/registration-conditions`](/engine/indirect-tax/registrations/v2/content/registration-conditions-POST) | POST | Get conditions for a registration type | | [`/registrations/v2/content/portal-fields`](/engine/indirect-tax/registrations/v2/content/portal-fields-POST) | POST | Get portal credential requirements | | [`/registrations/v2/content/tax-type-details`](/engine/indirect-tax/registrations/v2/content/tax-type-details-POST) | POST | Get tax type descriptions | ### Registration management | Endpoint | Method | Description | | -------------------------------------------------------------------------------------------- | ------ | ------------------------------- | | [`/registrations/v2`](/engine/indirect-tax/registrations/v2/registrations-v2-POST) | POST | Create a new registration | | [`/registrations/v2/list`](/engine/indirect-tax/registrations/v2/registrations-v2-GET) | POST | List registrations with filters | | [`/registrations/v2/{id}`](/engine/indirect-tax/registrations/v2/registrations-v2-id-GET) | GET | Get a single registration | | [`/registrations/v2/{id}`](/engine/indirect-tax/registrations/v2/registrations-v2-id-POST) | POST | Update a registration | | [`/registrations/v2/{id}`](/engine/indirect-tax/registrations/v2/registrations-v2-id-DELETE) | DELETE | Delete a registration | ### Registration lifecycle | Endpoint | Method | Description | | ------------------------------------------------------------------------------------------------------------------------------- | ------ | ----------------------------- | | [`/registrations/v2/{id}/archive`](/engine/indirect-tax/registrations/v2/registrations-v2-id-archive-POST) | POST | Archive a registration | | [`/registrations/v2/{id}/close`](/engine/indirect-tax/registrations/v2/registrations-v2-id-close-POST) | POST | Close a registration | | [`/registrations/v2/credentials/by-portal/{portal_id}`](/engine/indirect-tax/registrations/v2/registrations-v2-credentials-GET) | GET | Look up credentials by portal | ### Bulk operations | Endpoint | Method | Description | | ------------------------------------------------------------------------------------------------------------------------------------------------ | ------ | --------------------------------------------- | | [`/registrations/v2/bulk`](/engine/indirect-tax/registrations/v2/registrations-v2-bulk-POST) | POST | Create multiple registrations | | [`/registrations/v2/bulk/request-validation`](/engine/indirect-tax/registrations/v2/registrations-v2-bulk-POST#bulk-request-validation) | POST | Request validation for multiple registrations | | [`/registrations/v2/bulk/registration-status`](/engine/indirect-tax/registrations/v2/registrations-v2-bulk-POST#bulk-update-registration-status) | POST | Update status for multiple registrations | ### Tasks and form data | Endpoint | Method | Description | | ----------------------------------------------------------------------------------------------------------------------- | ------ | ----------------------------------------- | | [`/registrations/v2/tasks`](/engine/indirect-tax/registrations/v2/registrations-v2-tasks-GET) | GET | List registration tasks for a corporation | | [`/registrations/v2/{id}/form-data`](/engine/indirect-tax/registrations/v2/registrations-v2-form-data) | GET | Get supplementary form data | | [`/registrations/v2/{id}/form-data`](/engine/indirect-tax/registrations/v2/registrations-v2-form-data#update-form-data) | POST | Update supplementary form data | # List Registrations Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/registrations-v2-GET POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/list Retrieve all V2 registrations for a corporation with optional filters and pagination List all V2 registrations for a corporation. Supports filtering by country, state, jurisdiction type, registration status, validation status, and jurisdiction name search. Results are cursor-paginated. This endpoint uses POST (not GET) to support complex filtering via the request body. ## Request body The unique identifier for the corporation whose registrations you want to retrieve. Filter by ISO 3166-1 alpha-2 country codes. Maximum 100 items. Example: `["US", "DE"]` Filter by state or province codes. Maximum 100 items. Example: `["CA", "NY", "TX"]` Filter by jurisdiction type. Maximum 100 items. Values: `STATE_OR_PROVINCE`, `CITY`, `COUNTY`, `DISTRICT`, `LOCAL`, `COUNTRY`, `TERRITORY`, `TRADEBLOC` Search by jurisdiction name (partial match). Example: `"California"` or `"Germany"` Filter by registration status. Filter by validation status. Values: `PENDING`, `VALID`, `INVALID` Whether to include archived registrations in the results. Pagination cursor from a previous response. Leave empty for the first page. Maximum number of results to return (1–100). ```bash cURL - All theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/list' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000" }' ``` ```bash cURL - Filtered theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/list' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "countries": ["US"], "states": ["CA", "TX"], "validation_status": "PENDING" }' ``` ```json All registrations theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000" } ``` ```json By country and state theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "countries": ["US"], "states": ["CA", "NY", "TX"] } ``` ```json Include archived theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "include_archived": true } ``` ```json With pagination theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "limit": 25, "cursor": "encoded_cursor_string" } ``` ```json 200 theme={null} { "data": { "registrations": [ { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "registration_content_id": "REG_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequencies": ["QUARTERLY"], "jurisdiction_id": "JUR_US_STATE_CA", "jurisdiction_name": "California", "jurisdiction_type": "STATE_OR_PROVINCE", "registration_name": "Sales and Use Tax", "effective_start_date": "2024-01-01", "registered_by": "COMMENDA", "registration_status": "PENDING", "validation_status": "PENDING", "created_at": "2024-01-15T10:30:00Z" }, { "id": "8d9f7780-8536-51ef-a55c-c2851cbface8", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_STATE_CEN_48_RST", "registration_content_id": "REG_STATE_CEN_48_RST", "tax_types": ["RST"], "frequencies": ["MONTHLY"], "jurisdiction_id": "JUR_US_STATE_TX", "jurisdiction_name": "Texas", "jurisdiction_type": "STATE_OR_PROVINCE", "registration_name": "Sales and Use Tax", "effective_start_date": "2024-02-01", "registered_by": "API", "registration_status": "PENDING", "validation_status": "PENDING", "created_at": "2024-02-01T14:20:00Z" } ], "total": 12, "cursor": "encoded_next_page_cursor" } } ``` ```json 400 - Missing corporation ID theme={null} { "message": "Failed to parse request body.", "error": { "type": "CLIENT_INVALID_REQUEST_BODY", "title": "Failed to validate the request body", "detail": "corporation_id is required", "status": 400, "instance": "/api/v1/registrations/v2/list" } } ``` ## Related * [Get Registration](/engine/indirect-tax/registrations/v2/registrations-v2-id-GET) — Get details for a specific registration * [Create Registration](/engine/indirect-tax/registrations/v2/registrations-v2-POST) — Create a new V2 registration * [Tax Registrations V2 Overview](/engine/indirect-tax/registrations/v2/registrations-v2) — Registration concepts and lifecycle # Create Registration Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/registrations-v2-POST POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2 Create a new V2 tax registration for a corporation Create a registration to enable tax calculations and automated filing for a jurisdiction. Before calling this endpoint, use the [V2 content endpoints](/engine/indirect-tax/registrations/v2/content/content-v2) to discover available jurisdictions and get the required `registration_tax_type_id`. ## Request body The unique identifier (UUID) for the corporation. The content ID identifying the jurisdiction and tax type combination. Obtain this from the [Available Registrations](/engine/indirect-tax/registrations/v2/content/available-registrations-POST) endpoint. Example: `"REG_STATE_CEN_06_RST"` (California Retail Sales Tax) Array of tax types to register for. Must be valid for the selected `registration_tax_type_id`. Include the primary tax type and all required related types (where `optional: false` in the content response). Minimum 1, maximum 100 items. Example: `["RST", "DTT"]` Array of filing frequencies. Must exactly match one of the allowed frequency combinations from the content response. Maximum 100 items. This field is optional — if omitted, the registration is created without a filing frequency set. Example: `["QUARTERLY"]` or `["QUARTERLY", "ANNUAL_RECONCILIATION"]` ISO date (YYYY-MM-DD) when the registration became or becomes effective. Who is creating this registration. Defaults to `COMMENDA` if not provided. Values: `COMMENDA`, `API`, `USER` Your tax registration ID, permit number, or account number issued by the tax authority. Reference to stored portal credentials (UUID). Can be added later via update. Set to `true` to enable Commenda-managed filing for this registration. When enabled, Commenda handles the filing process on your behalf. Defaults to `false`. UUID of an existing active domestic registration. Required for Union OSS registrations that have a `PREREQUISITE_REGISTRATION` condition. The referenced registration must belong to the same corporation and be in an EU country where your business has a qualifying establishment. Content ID of the member country to register through. Required for registrations with a `MEMBER_COUNTRY_TO_REGISTER_THROUGH` condition (Non-Union OSS, IOSS). Example: `"REG_COUNTRY_DE_3001_VAT"` ## Validation rules | Rule | Description | | ------------------------ | ------------------------------------------------------------------------------------------ | | **Tax types** | Must include all mandatory types and only allowed types for the content ID | | **Frequencies** | If provided, must exactly match one allowed frequency combination | | **Duplicate prevention** | Only one active (non-archived) registration per `registration_tax_type_id` per corporation | | **Conditions** | Prerequisites must be met, mutually exclusive registrations must not be active | ### EU establishment rules For EU trade bloc registrations, additional establishment checks are enforced automatically: | Scheme | Requirement | | ----------------- | ---------------------------------------------------------------------------------------------------------- | | **Union OSS** | Your business must have a qualifying EU establishment in the same country as the member state registration | | **Non-Union OSS** | Your business must **not** have any qualifying EU establishment | Qualifying establishment types: headquarters, branch office, warehouse, factory, retail location, dependent agent. ```bash cURL - US state theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequencies": ["QUARTERLY"], "effective_start_date": "2024-01-01" }' ``` ```json US state theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequencies": ["QUARTERLY"], "effective_start_date": "2024-01-01" } ``` ```json Minimal theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_STATE_CEN_48_RST", "tax_types": ["RST"], "frequencies": ["MONTHLY"] } ``` ```json Union OSS theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_TRADEBLOC_EU_3000_UOSS_VAT", "tax_types": ["VAT"], "frequencies": ["QUARTERLY"], "member_state_registration_id": "8a1b2c3d-4e5f-6789-abcd-ef0123456789" } ``` ```json Non-Union OSS theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_TRADEBLOC_EU_3000_NUOSS_VAT", "tax_types": ["VAT"], "frequencies": ["QUARTERLY"], "registered_through_registration_tax_type_id": "REG_COUNTRY_DE_3001_VAT" } ``` ```json 201 theme={null} { "message": "Registration created successfully.", "data": { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequencies": ["QUARTERLY"], "jurisdiction_id": "JUR_US_STATE_CA", "jurisdiction_name": "California", "jurisdiction_type": "STATE_OR_PROVINCE", "registration_name": "Sales and Use Tax", "effective_start_date": "2024-01-01", "registered_by": "COMMENDA", "managed_filing_enabled": false, "registration_status": "PENDING", "validation_status": "PENDING", "created_at": "2024-01-15T10:30:00Z" } } ``` ```json 400 - Content not found theme={null} { "error": { "type": "CONTENT_NOT_FOUND", "title": "Registration content not found.", "detail": "The registration_tax_type_id 'INVALID_ID' does not exist.", "status": 400, "instance": "/api/v1/registrations/v2" } } ``` ```json 400 - Duplicate registration theme={null} { "error": { "type": "DUPLICATE_REGISTRATION", "title": "A registration already exists.", "detail": "An active registration already exists for this registration_tax_type_id and corporation.", "status": 400, "instance": "/api/v1/registrations/v2" } } ``` ```json 400 - Invalid tax type theme={null} { "error": { "type": "INVALID_TAX_TYPE", "title": "Invalid tax type for this registration.", "detail": "The provided tax types do not match the allowed options for this registration.", "status": 400, "instance": "/api/v1/registrations/v2" } } ``` ```json 400 - Invalid frequency theme={null} { "error": { "type": "INVALID_FREQUENCY", "title": "Invalid frequency for this registration.", "detail": "The provided frequencies do not match any allowed frequency combination.", "status": 400, "instance": "/api/v1/registrations/v2" } } ``` ```json 400 - Prerequisite not met theme={null} { "error": { "type": "PREREQUISITE_NOT_MET", "title": "Prerequisite registration required.", "detail": "At least one prerequisite registration must be active before creating this registration.", "status": 400, "instance": "/api/v1/registrations/v2" } } ``` ```json 400 - Mutually exclusive conflict theme={null} { "error": { "type": "MUTUALLY_EXCLUSIVE_CONFLICT", "title": "Registration conflict.", "detail": "This registration conflicts with an existing active registration.", "status": 400, "instance": "/api/v1/registrations/v2" } } ``` ## Related * [V2 Registration Content](/engine/indirect-tax/registrations/v2/content/content-v2) — Discover jurisdictions and get content IDs * [Update Registration V2](/engine/indirect-tax/registrations/v2/registrations-v2-id-POST) — Add credentials or update fields * [Registration Conditions](/engine/indirect-tax/registrations/v2/content/registration-conditions-POST) — Check conditions before creating * [Tax Registrations V2 Overview](/engine/indirect-tax/registrations/v2/registrations-v2) — Full workflow # Bulk operations Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/registrations-v2-bulk-POST Create, validate, and update multiple registrations in a single request Use bulk endpoints to manage multiple V2 registrations at once. Each operation processes items independently — individual failures do not block the rest of the batch. ## Bulk create registrations Create multiple registrations for a corporation in one request. Each item follows the same validation rules as the [single create endpoint](/engine/indirect-tax/registrations/v2/registrations-v2-POST). ``` POST /registrations/v2/bulk ``` ### Request body The corporation UUID that owns the registrations. Array of registration objects (minimum 1). Each object accepts: | Field | Type | Required | Description | | --------------------------------------------- | --------- | -------- | ------------------------------------------------------- | | `registration_tax_type_id` | string | Yes | Content ID for the jurisdiction and tax type | | `tax_types` | string\[] | Yes | Tax types to register for (minimum 1) | | `frequencies` | string\[] | Yes | Filing frequencies (minimum 1) | | `effective_start_date` | string | No | ISO date (YYYY-MM-DD) | | `registered_by` | string | No | `COMMENDA`, `API`, or `USER` | | `tax_registration_number` | string | No | Permit or account number from the tax authority | | `credential_id` | string | No | UUID of stored portal credentials | | `member_state_registration_id` | string | No | UUID of prerequisite domestic registration (Union OSS) | | `registered_through_registration_tax_type_id` | string | No | Content ID for the member country (Non-Union OSS, IOSS) | ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/bulk' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registrations": [ { "registration_tax_type_id": "REG_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequencies": ["QUARTERLY"], "effective_start_date": "2024-01-01" }, { "registration_tax_type_id": "REG_STATE_CEN_48_RST", "tax_types": ["RST"], "frequencies": ["MONTHLY"] } ] }' ``` ```json Request body theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registrations": [ { "registration_tax_type_id": "REG_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequencies": ["QUARTERLY"], "effective_start_date": "2024-01-01" }, { "registration_tax_type_id": "REG_STATE_CEN_48_RST", "tax_types": ["RST"], "frequencies": ["MONTHLY"] } ] } ``` ```json 201 theme={null} { "message": "Bulk registration completed.", "registrations": [ { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "status": "CREATED" }, { "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab", "registration_tax_type_id": "REG_STATE_CEN_48_RST", "status": "CREATED" } ] } ``` ```json 201 - Partial failure theme={null} { "message": "Bulk registration completed.", "registrations": [ { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "status": "CREATED" }, { "id": "", "registration_tax_type_id": "INVALID_ID", "status": "FAILED", "error": "The registration_tax_type_id 'INVALID_ID' does not exist." } ] } ``` *** ## Bulk request validation Request Commenda validation for multiple registrations at once. This triggers the same verification process as the individual validation request. ``` POST /registrations/v2/bulk/request-validation ``` ### Request body The corporation UUID. Array of registration UUIDs to validate (minimum 1). ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/bulk/request-validation' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_ids": [ "7c9e6679-7425-40de-944b-e07fc1f90ae7", "a1b2c3d4-5678-90ab-cdef-1234567890ab" ] }' ``` ```json Request body theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_ids": [ "7c9e6679-7425-40de-944b-e07fc1f90ae7", "a1b2c3d4-5678-90ab-cdef-1234567890ab" ] } ``` ```json 200 theme={null} { "message": "Bulk validation request completed.", "results": [ { "registration_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "success": true }, { "registration_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab", "success": true } ] } ``` ```json 200 - Partial failure theme={null} { "message": "Bulk validation request completed.", "results": [ { "registration_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "success": true }, { "registration_id": "00000000-0000-0000-0000-000000000000", "success": false, "error": "Registration not found." } ] } ``` *** ## Bulk update registration status Update the registration status for multiple registrations simultaneously. ``` POST /registrations/v2/bulk/registration-status ``` ### Request body The corporation UUID. Array of registration UUIDs to update (minimum 1). The new status to apply to all specified registrations. Values: `REGISTERED`, `REGISTRATION_IN_PROGRESS`, `PENDING` ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/bulk/registration-status' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_ids": [ "7c9e6679-7425-40de-944b-e07fc1f90ae7", "a1b2c3d4-5678-90ab-cdef-1234567890ab" ], "registration_status": "REGISTERED" }' ``` ```json Request body theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_ids": [ "7c9e6679-7425-40de-944b-e07fc1f90ae7", "a1b2c3d4-5678-90ab-cdef-1234567890ab" ], "registration_status": "REGISTERED" } ``` ```json 200 theme={null} { "message": "Bulk status update completed.", "results": [ { "registration_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "success": true }, { "registration_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab", "success": true } ] } ``` ## When to use bulk operations * **Onboarding** — Register a corporation across multiple jurisdictions in a single call instead of making separate requests * **Validation sweeps** — Request validation for all pending registrations at once * **Status updates** — Mark multiple registrations as active after receiving confirmation from tax authorities Each item in a bulk request is processed independently. If one item fails validation (e.g., duplicate registration), the remaining items still succeed. Always check the `status` or `success` field on each result item. ## Related * [Create Registration](/engine/indirect-tax/registrations/v2/registrations-v2-POST) — Create a single registration * [Tax Registrations V2 Overview](/engine/indirect-tax/registrations/v2/registrations-v2) — Full workflow and concepts # Credential Lookup Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/registrations-v2-credentials-GET GET https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/credentials/by-portal/{portal_id} Look up whether credentials exist for a corporation and portal Check whether a corporation already has stored credentials for a specific tax portal. Use this to avoid prompting users for credentials they've already provided. ## Path parameters The portal ID to look up credentials for. Example: `"PORTAL_CA_CDTFA"` ## Query parameters The corporation ID to check credentials for. ```bash cURL theme={null} curl --request GET \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/credentials/by-portal/PORTAL_CA_CDTFA?corporation_id=550e8400-e29b-41d4-a716-446655440000' \ --header 'Authorization: Bearer ' ``` ```json 200 - Credential found theme={null} { "data": { "credential_id": "cred_abc123def456", "found": true } } ``` ```json 200 - No credential theme={null} { "data": { "found": false } } ``` This endpoint returns `found: false` (not an error) when no credentials exist for the portal and corporation combination. ## Related * [Portal Fields](/engine/indirect-tax/registrations/v2/content/portal-fields-POST) — Get credential field requirements for a portal * [Update Registration](/engine/indirect-tax/registrations/v2/registrations-v2-id-POST) — Attach a credential to a registration # Registration form data Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/registrations-v2-form-data Retrieve and update supplementary form data for V2 registrations Some registrations require additional information beyond the core registration fields — such as tax account details, officer information, or cross-border trade declarations. Use the form data endpoints to retrieve and submit this information. ## Get form data Retrieve the current form data for a registration, including officer details, cross-border trade fields, and any metadata collected during the registration process. ``` GET /registrations/v2/{registration_id}/form-data ``` ### Path parameters The unique identifier (UUID) of the registration. ### Query parameters The corporation UUID. ### Response fields | Field | Type | Description | | --------------------------- | -------------- | -------------------------------------------------------- | | `registration_id` | string | The registration UUID | | `corporation_id` | string | The corporation identifier | | `jurisdiction_id` | string \| null | Jurisdiction identifier | | `jurisdiction_type` | string \| null | Jurisdiction type (e.g., `STATE_OR_PROVINCE`, `COUNTRY`) | | `jurisdiction_name` | string \| null | Human-readable jurisdiction name | | `sales_tax_registration_id` | string \| null | Internal registration reference | | `officer` | object \| null | Responsible officer details (see below) | | `metadata` | object \| null | Additional collected data | #### Officer object When present, the `officer` object contains details about the person responsible for the registration: | Field | Type | Description | | ------------------------ | ----------------- | ----------------------------------------------------------------------------------------------- | | `id` | number | Officer identifier | | `first_name` | string \| null | First name | | `middle_name` | string \| null | Middle name | | `last_name` | string \| null | Last name | | `email` | string \| null | Email address | | `ssn` | string \| null | Social security number (masked) | | `has_no_ssn` | boolean \| null | Whether the officer has no SSN | | `job_title` | string \| null | Job title or role | | `roles` | string\[] \| null | Assigned roles | | `employment_start_date` | string \| null | Employment start date | | `date_of_birth` | string \| null | Date of birth | | `country_of_citizenship` | string \| null | Country of citizenship | | `home_address` | object \| null | Home address with `address_line_1`, `address_line_2`, `city`, `state`, `postal_code`, `country` | | `government_id` | object \| null | Government ID document with `id`, `file_name`, `file_url` | ```bash cURL theme={null} curl --request GET \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/7c9e6679-7425-40de-944b-e07fc1f90ae7/form-data?corporation_id=550e8400-e29b-41d4-a716-446655440000' \ --header 'Authorization: Bearer ' ``` ```json 200 theme={null} { "registration_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "jurisdiction_id": "JUR_EU_COUNTRY_DE", "jurisdiction_type": "COUNTRY", "jurisdiction_name": "Germany", "sales_tax_registration_id": "abc123", "officer": { "id": 42, "first_name": "Jane", "last_name": "Doe", "email": "jane@example.com", "job_title": "CFO", "roles": ["DIRECTOR"], "country_of_citizenship": "US", "home_address": { "address_line_1": "123 Main St", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" } }, "metadata": null } ``` *** ## Update form data Submit or update supplementary form data for a registration. Use this to provide tax account details, assign a responsible officer, or declare cross-border trade information. ``` POST /registrations/v2/{registration_id}/form-data ``` ### Path parameters The unique identifier (UUID) of the registration. ### Request body The corporation UUID. ISO date (YYYY-MM-DD) when the tax account was first established with the jurisdiction. The calendar year when the corporation first made a taxable sale in this jurisdiction. The ID of the officer responsible for this registration. Must be a valid officer associated with the corporation. Whether the corporation conducts intra-community trade (relevant for EU VAT registrations). Whether the corporation imports or exports goods in this jurisdiction. The currency used for transactions in this jurisdiction (ISO 4217 code, e.g., `EUR`, `USD`). ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/7c9e6679-7425-40de-944b-e07fc1f90ae7/form-data' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "officer_id": 42, "intra_community_trade": true, "imports_or_exports_goods": false, "currency": "EUR" }' ``` ```json Request body theme={null} { "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "officer_id": 42, "intra_community_trade": true, "imports_or_exports_goods": false, "currency": "EUR" } ``` ```json 200 theme={null} { "message": "Form data updated successfully." } ``` ## When to use form data * **EU registrations** — Provide cross-border trade declarations (`intra_community_trade`, `imports_or_exports_goods`) and the operating currency * **Managed registrations** — Assign a responsible officer and provide tax account history when Commenda is handling the registration on your behalf * **Task completion** — Some [registration tasks](/engine/indirect-tax/registrations/v2/registrations-v2-tasks-GET) require you to submit form data before the registration can proceed All fields in the update request are optional. You can submit partial updates — only the provided fields are changed, and existing values for other fields are preserved. ## Related * [List Registration Tasks](/engine/indirect-tax/registrations/v2/registrations-v2-tasks-GET) — View pending tasks that may require form data * [Get Registration](/engine/indirect-tax/registrations/v2/registrations-v2-id-GET) — View registration details * [Tax Registrations V2 Overview](/engine/indirect-tax/registrations/v2/registrations-v2) — Full workflow and concepts # Delete Registration Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/registrations-v2-id-DELETE DELETE https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/{tax_registration_id} Permanently delete a V2 registration Permanently delete a V2 registration. This action cannot be undone. Registrations with `validation_status: VALID` cannot be deleted. Contact [Commenda support](mailto:support@commenda.io) if you need to remove a validated registration. ## Path parameters The unique identifier (UUID) of the registration to delete. ## When to use delete vs. close vs. archive | Action | Use case | Effect | | ------------------------------------------------------------------------------------- | --------------------------------------------------- | -------------------------------------------------- | | **Delete** | Remove a duplicate, test, or erroneous registration | Permanently removes the registration | | [**Close**](/engine/indirect-tax/registrations/v2/registrations-v2-id-close-POST) | Stop selling in a jurisdiction on a specific date | Sets end date, preserves historical records | | [**Archive**](/engine/indirect-tax/registrations/v2/registrations-v2-id-archive-POST) | Completely disable a registration | Stops calculations, hidden from default list views | ## Deletable registrations A registration can only be deleted when `validation_status` is **not** `VALID`. This means registrations with status `PENDING` or `INVALID` can be deleted. ```bash cURL theme={null} curl --request DELETE \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/7c9e6679-7425-40de-944b-e07fc1f90ae7' \ --header 'Authorization: Bearer ' ``` ```json 200 theme={null} { "message": "Registration deleted successfully." } ``` ```json 400 - Cannot delete valid registration theme={null} { "error": { "type": "CANNOT_DELETE_VALID", "title": "Cannot delete registration.", "detail": "Registration with validation_status of VALID cannot be deleted; please contact the Commenda team.", "status": 400, "instance": "/api/v1/registrations/v2/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` ```json 404 - Not found theme={null} { "error": { "type": "REGISTRATION_NOT_FOUND", "title": "Registration not found.", "status": 404, "instance": "/api/v1/registrations/v2/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` ## Related * [Close Registration](/engine/indirect-tax/registrations/v2/registrations-v2-id-close-POST) — End on a specific date * [Archive Registration](/engine/indirect-tax/registrations/v2/registrations-v2-id-archive-POST) — Completely disable * [Tax Registrations V2 Overview](/engine/indirect-tax/registrations/v2/registrations-v2) — Registration lifecycle # Get Registration Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/registrations-v2-id-GET GET https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/{tax_registration_id} Retrieve details of a specific V2 registration by ID Retrieve the full details of a V2 registration, including its current status, jurisdiction information, and configuration. ## Path parameters The unique identifier (UUID) of the registration to retrieve. ## Response fields | Field | Type | Description | | --------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `id` | string | Unique identifier for the registration | | `corporation_id` | string | The corporation this registration belongs to | | `registration_tax_type_id` | string | Content ID identifying the jurisdiction and tax type | | `registration_content_id` | string | Bare registration content ID for the jurisdiction (e.g., `REG_COUNTRY_DE_3001_VAT`). Use this for exact-match comparisons against the `recommended_registration_content_ids` returned by exposure webhooks and nexus rules. May be empty for legacy registrations. | | `tax_types` | array | Tax types registered for (e.g., `["RST", "DTT"]`) | | `frequencies` | array | Filing frequencies (e.g., `["QUARTERLY"]`) | | `jurisdiction_id` | string | Unique identifier for the jurisdiction | | `jurisdiction_name` | string | Human-readable name of the jurisdiction | | `jurisdiction_type` | string | Type: `STATE_OR_PROVINCE`, `CITY`, `COUNTY`, `COUNTRY`, `TRADEBLOC`, etc. | | `registration_name` | string | Human-readable name of the registration | | `effective_start_date` | string | When the registration became effective (YYYY-MM-DD) | | `effective_end_date` | string | When the registration ended (YYYY-MM-DD), if closed | | `tax_registration_number` | string | Tax authority issued ID or permit number | | `registered_by` | string | Who created the registration: `API`, `USER`, `COMMENDA` | | `credential_id` | string | Reference to stored portal credentials | | `managed_filing_enabled` | boolean | Whether Commenda-managed filing is enabled for this registration | | `registration_status` | string | Current registration status | | `validation_status` | string | `PENDING`, `VALID`, or `INVALID` | | `registered_through_registration_tax_type_id` | string | Content ID of the country registered through (for Non-Union OSS, IOSS) | | `member_state_registration_id` | string | UUID of the linked domestic registration (for Union OSS) | | `archived_at` | string | Timestamp if archived, otherwise null | | `created_at` | string | When the registration was created | | `updated_at` | string | When the registration was last updated | ```bash cURL theme={null} curl --request GET \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/7c9e6679-7425-40de-944b-e07fc1f90ae7' \ --header 'Authorization: Bearer ' ``` ```json 200 theme={null} { "data": { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "registration_content_id": "REG_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequencies": ["QUARTERLY"], "jurisdiction_id": "JUR_US_STATE_CA", "jurisdiction_name": "California", "jurisdiction_type": "STATE_OR_PROVINCE", "registration_name": "Sales and Use Tax", "effective_start_date": "2024-01-15", "managed_filing_enabled": false, "registered_by": "COMMENDA", "registration_status": "PENDING", "validation_status": "PENDING", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-20T15:45:00Z" } } ``` ```json 404 - Not found theme={null} { "error": { "type": "REGISTRATION_NOT_FOUND", "title": "Registration not found.", "detail": "The registration does not exist or you don't have access.", "status": 404, "instance": "/api/v1/registrations/v2/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` ```json 400 - Invalid UUID theme={null} { "error": { "type": "INVALID_INPUT", "title": "Invalid registration ID.", "detail": "The provided ID is not a valid UUID.", "status": 400, "instance": "/api/v1/registrations/v2/not-a-uuid" } } ``` ## Related * [List Registrations](/engine/indirect-tax/registrations/v2/registrations-v2-GET) — Get all registrations with filters * [Update Registration](/engine/indirect-tax/registrations/v2/registrations-v2-id-POST) — Modify this registration * [Tax Registrations V2 Overview](/engine/indirect-tax/registrations/v2/registrations-v2) — Registration concepts and lifecycle # Update Registration Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/registrations-v2-id-POST POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/{tax_registration_id} Update an existing V2 registration's details Update a V2 registration to modify tax types, frequencies, credentials, and other fields. Uses merge semantics — only fields present in the request body are updated; omitted fields keep their current values. ## Path parameters The unique identifier (UUID) of the registration to update. ## Request body All fields are optional. Only the fields you provide will be updated. Array of tax types. Must be valid for the registration's content ID. Minimum 1, maximum 100 items. Array of filing frequencies. Must exactly match one allowed frequency combination from the content. Minimum 1, maximum 100 items. ISO date (YYYY-MM-DD) when the registration became or becomes effective. Pass an empty string to clear the value. Your tax registration ID or permit number. Pass an empty string to clear the value. Reference to stored portal credentials (UUID). Pass an empty string to clear the value. Set to `true` to enable Commenda-managed filing for this registration. When enabled, Commenda handles the filing process on your behalf. Who created the registration. Values: `COMMENDA`, `API`, `USER` ## Validation rules When updating `tax_types` or `frequencies`, the new values are re-validated against the registration's content: * **Tax types** must include all mandatory types and only allowed types * **Frequencies** must exactly match one allowed frequency combination ```bash cURL - Add credentials theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/7c9e6679-7425-40de-944b-e07fc1f90ae7' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "tax_registration_number": "123-456789-00", "credential_id": "cred_abc123def456" }' ``` ```json Add credentials theme={null} { "tax_registration_number": "123-456789-00", "credential_id": "cred_abc123def456" } ``` ```json Change frequency theme={null} { "frequencies": ["MONTHLY"] } ``` ```json Enable managed filing theme={null} { "managed_filing_enabled": true } ``` ```json Update multiple fields theme={null} { "tax_types": ["RST", "DTT"], "frequencies": ["QUARTERLY"], "effective_start_date": "2024-02-01" } ``` ```json Clear a field theme={null} { "tax_registration_number": "" } ``` ```json 200 theme={null} { "message": "Registration updated successfully.", "data": { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "corporation_id": "550e8400-e29b-41d4-a716-446655440000", "registration_tax_type_id": "REG_STATE_CEN_06_RST", "tax_types": ["RST", "DTT"], "frequencies": ["QUARTERLY"], "jurisdiction_id": "JUR_US_STATE_CA", "jurisdiction_name": "California", "jurisdiction_type": "STATE_OR_PROVINCE", "registration_name": "Sales and Use Tax", "effective_start_date": "2024-02-01", "tax_registration_number": "123-456789-00", "credential_id": "cred_abc123def456", "managed_filing_enabled": false, "registered_by": "COMMENDA", "registration_status": "PENDING", "validation_status": "PENDING", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-02-15T09:00:00Z" } } ``` ```json 400 - Invalid tax type theme={null} { "error": { "type": "INVALID_TAX_TYPE", "title": "Invalid tax type for this registration.", "detail": "The provided tax types do not match the allowed options.", "status": 400, "instance": "/api/v1/registrations/v2/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` ```json 400 - Invalid frequency theme={null} { "error": { "type": "INVALID_FREQUENCY", "title": "Invalid frequency for this registration.", "detail": "The provided frequencies do not match any allowed frequency combination.", "status": 400, "instance": "/api/v1/registrations/v2/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` ```json 404 - Not found theme={null} { "error": { "type": "REGISTRATION_NOT_FOUND", "title": "Registration not found.", "status": 404, "instance": "/api/v1/registrations/v2/7c9e6679-7425-40de-944b-e07fc1f90ae7" } } ``` ## Related * [Get Registration](/engine/indirect-tax/registrations/v2/registrations-v2-id-GET) — View registration details * [Create Registration](/engine/indirect-tax/registrations/v2/registrations-v2-POST) — Create a new registration * [Tax Registrations V2 Overview](/engine/indirect-tax/registrations/v2/registrations-v2) — Registration concepts and lifecycle # Archive Registration Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/registrations-v2-id-archive-POST POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/{tax_registration_id}/archive Archive a V2 registration to stop tax calculations and hide from default views Archive a registration to completely exclude it from tax calculations and hide it from default list views. Archived registrations are preserved for historical records but no longer participate in tax processing. ## Path parameters The unique identifier (UUID) of the registration to archive. ## What happens when you archive * **Tax calculations stop** — The registration is no longer considered when calculating taxes * **Hidden from views** — Excluded from list results unless you set `include_archived: true` * **Data preserved** — All historical data remains intact for reference ## Archive vs. close vs. delete | Action | Use case | Tax calculations | Reversible | | --------------------------------------------------------------------------------- | ----------------------- | ------------------------ | --------------- | | **Archive** | Completely disable | Stopped entirely | Contact support | | [**Close**](/engine/indirect-tax/registrations/v2/registrations-v2-id-close-POST) | Stop on a specific date | Active within date range | No | | [**Delete**](/engine/indirect-tax/registrations/v2/registrations-v2-id-DELETE) | Remove entirely | N/A — data removed | No | If you need to stop collecting tax starting from a specific date but preserve calculations for the historical period, use [Close](/engine/indirect-tax/registrations/v2/registrations-v2-id-close-POST) instead. ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/7c9e6679-7425-40de-944b-e07fc1f90ae7/archive' \ --header 'Authorization: Bearer ' ``` ```json 200 theme={null} { "message": "Registration archived successfully." } ``` ```json 404 - Not found theme={null} { "error": { "type": "REGISTRATION_NOT_FOUND", "title": "Registration not found.", "status": 404, "instance": "/api/v1/registrations/v2/7c9e6679-7425-40de-944b-e07fc1f90ae7/archive" } } ``` ## Viewing archived registrations To include archived registrations in list results, set `include_archived: true`: ```json theme={null} POST /registrations/v2/list { "corporation_id": "your-corp-id", "include_archived": true } ``` Archived registrations will have a non-null `archived_at` timestamp. ## Related * [Close Registration](/engine/indirect-tax/registrations/v2/registrations-v2-id-close-POST) — Stop on a specific date (preserves historical calculations) * [Delete Registration](/engine/indirect-tax/registrations/v2/registrations-v2-id-DELETE) — Permanently remove * [List Registrations](/engine/indirect-tax/registrations/v2/registrations-v2-GET) — Use `include_archived: true` to see archived registrations # Close Registration Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/registrations-v2-id-close-POST POST https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/{tax_registration_id}/close Close a V2 registration by setting an effective end date Close a registration when you stop doing business in a jurisdiction. This sets an `effective_end_date` and stops tax calculations for transactions after that date. ## Path parameters The unique identifier (UUID) of the registration to close. ## Request body ISO date (YYYY-MM-DD) when the registration ends. Must not be before the `effective_start_date`. Example: `"2024-12-31"` ## Effect of closing After the `effective_end_date`: 1. **Tax calculations** — The `/calculate` endpoint returns zero tax for this jurisdiction 2. **Filing** — No returns are filed for periods after the end date 3. **Historical data** — All transaction and filing history is preserved Closing a registration does **not** affect filings for periods up to and including the end date. ```bash cURL theme={null} curl --request POST \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/7c9e6679-7425-40de-944b-e07fc1f90ae7/close' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{"effective_end_date": "2024-12-31"}' ``` ```json Request body theme={null} { "effective_end_date": "2024-12-31" } ``` ```json 200 theme={null} { "message": "Registration closed successfully." } ``` ```json 400 - Invalid end date theme={null} { "error": { "type": "INVALID_EFFECTIVE_END_DATE", "title": "Invalid effective_end_date.", "detail": "Effective end date cannot be before the effective start date.", "status": 400, "instance": "/api/v1/registrations/v2/7c9e6679-7425-40de-944b-e07fc1f90ae7/close" } } ``` ```json 404 - Not found theme={null} { "error": { "type": "REGISTRATION_NOT_FOUND", "title": "Registration not found.", "status": 404, "instance": "/api/v1/registrations/v2/7c9e6679-7425-40de-944b-e07fc1f90ae7/close" } } ``` ## Related * [Archive Registration](/engine/indirect-tax/registrations/v2/registrations-v2-id-archive-POST) — Completely disable (stops all calculations) * [Tax Registrations V2 Overview](/engine/indirect-tax/registrations/v2/registrations-v2) — Registration lifecycle # List registration tasks Source: https://docs.commenda.io/engine/indirect-tax/registrations/v2/registrations-v2-tasks-GET Retrieve pending tasks for a corporation's V2 registrations Retrieve all active registration tasks for a corporation. Tasks represent actions that need to be completed as part of the registration process — such as document submission, information verification, or Commenda team review. ``` GET /registrations/v2/tasks ``` ## Query parameters The corporation UUID to retrieve tasks for. ## Response Returns a list of tasks associated with the corporation's V2 registrations. | Field | Type | Description | | -------------------- | ------ | ---------------------------------------------------- | | `id` | string | Unique task identifier | | `task_id` | string | Task type identifier | | `title` | string | Human-readable description of what the task requires | | `status` | string | Current task status | | `assignee_type` | string | Who is responsible (`USER` or `AGENT`) | | `registration_id` | string | The registration this task belongs to | | `registration_name` | string | Human-readable name of the registration | | `service_request_id` | string | Associated service request identifier | ```bash cURL theme={null} curl --request GET \ --url 'https://transaction-tax.api.in.commenda.io/api/v1/registrations/v2/tasks?corporation_id=550e8400-e29b-41d4-a716-446655440000' \ --header 'Authorization: Bearer ' ``` ```json 200 theme={null} { "tasks": [ { "id": "d290f1ee-6c54-4b01-90e6-d701748f0851", "task_id": "SUBMIT_DOCUMENTS", "title": "Submit required documents for California Sales Tax", "status": "PENDING", "assignee_type": "USER", "registration_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "registration_name": "California Sales and Use Tax", "service_request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479" }, { "id": "e290f1ee-6c54-4b01-90e6-d701748f0852", "task_id": "REVIEW_APPLICATION", "title": "Commenda team is reviewing the registration", "status": "IN_PROGRESS", "assignee_type": "AGENT", "registration_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "registration_name": "California Sales and Use Tax", "service_request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479" } ] } ``` ```json 200 - No tasks theme={null} { "tasks": [] } ``` ## Task types Tasks are automatically created when you initiate a registration through Commenda's managed process. Each task is assigned to either you (`USER`) or the Commenda team (`AGENT`). * **User tasks** require action from you, such as providing additional information or uploading documents * **Agent tasks** are handled by the Commenda team and require no action from you — they serve as progress indicators Poll this endpoint to track the progress of registrations that are being processed by Commenda. When all tasks for a registration are complete, the registration status will be updated accordingly. ## Related * [Get Registration](/engine/indirect-tax/registrations/v2/registrations-v2-id-GET) — View registration details and status * [Registration Form Data](/engine/indirect-tax/registrations/v2/registrations-v2-form-data) — Provide additional information required by tasks * [Tax Registrations V2 Overview](/engine/indirect-tax/registrations/v2/registrations-v2) — Full workflow and concepts # Bulk Transactions Source: https://docs.commenda.io/engine/indirect-tax/transaction/bulk-transactions Utility for sellers to bulk upload transactions. ## Overview Commenda uses tax transactions to calculate the seller's tax obligations for filings and registration threshold tracking. In cases where sellers have been selling in various US states prior to onboarding to Commenda, some retroactive analysis will be necessary for accurate registration threshold evaluation. ### Usage Files will be uploaded through a `POST` to the `transactions/bulk` endpoint. They must be exactly the correct format, and are limited to 50 MB. ### Error Handling Default behavior is to load valid rows, and return an array detailing which rows were unable to be loaded, with the error associated with the row. ### CSV Format Files must be uploaded in CSV format, with the headers specified in our bulk uploads template. | Column Header | Required | Format | Description | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | corporation\_id | true | string (UUID) | The ID of the corporation whose transactions are being uploaded | | process\_code | true | [Process Code](#process-code) | A code indicating the process being performed | | transaction\_type | true | [Transaction Type](#transaction-type-code) | A code indicating the type of transaction (SALE, RETURN, or PURCHASE) | | transaction\_status | false | string | Status of the transaction. Valid values: UNCOMMITTED, COMMITTED, LOCKED, VOIDED | | invoice\_number | true | string | A unique ID for this invoice | | transacted\_at | true | ISO-8601 date string | The date on which the transaction occurred, or the date on which tax liability should be recognized. | | reporting\_date\_override | false | ISO-8601 date string | Optional date to control when the transaction appears in reports. | | calculation\_date\_override | false | ISO-8601 date string | Optional date to use for tax rate lookups. | | tax\_date\_override | false | ISO-8601 date string | Optional date to use for tax date override. | | line\_number | false | integer | If this is an invoice with multiple lines, this line number will be used to uniquely identify individual lines of the invoice. For RETURN transactions with line-level returns, this should match the line\_number from the original invoice. | | price\_per\_unit | true | number | Price per unit of the product sold on this line item. For RETURN transactions, this can be negative when used with positive quantity. | | quantity | true | number | Number of units of product sold/returned. For RETURN transactions, this can be negative when used with positive price\_per\_unit. | | discount | false | number >= 0 | Discount applied to this line item. Handle invoice-level discounts by distributing them evenly across line items. | | item\_shipping | false | number >= 0 | Line-item-level shipping cost. | | item\_handling | false | number >= 0 | Line-item-level handling cost. | | item\_tax | false | number >= 0 | Tax collected on this line item. Will be used for filing. | | tax\_included | true | boolean | Whether the pricing of this product is intended to be tax-inclusive. | | product\_id | false | string (UUID) | The ID of the sold product in Commenda's platform. Cannot be used together with product\_sku. | | product\_source\_platform\_id | false | string | The unique ID for this product in the source platform. | | product\_sku | false | string | A unique string used by the seller to identify the product being sold. Cannot be used together with product\_id. | | product\_taxability\_code | false | [Product Taxability Code](/engine/indirect-tax/taxcode) | A code used to identify the type of product being sold, and whether the product is taxable in the destination jurisdiction. Defaults to `TPP` if not set. | | customer\_id | false | string (UUID) | The ID of the purchasing customer in Commenda's platform. | | customer\_source\_platform\_id | false | string | The unique ID for this customer in the source platform. | | source\_platform | false | [Source Platform](#source-platform) | A code indicating the integration via which the transaction entered Commenda's system. This is not meant to indicate the platform on which the transaction took place. Must be provided together with source\_platform\_id. | | source\_platform\_id | false | string | The unique ID for this transaction or invoice in the source platform. This field should only be used for integrations. Must be provided together with source\_platform. | | exemption\_reason | false | [Exemption Reason](#exemption-reason) | During import, this field can be used to indicate that the transaction is tax-exempt because the purchaser is exempt. | | exemption\_certificate\_id | false | string (UUID) | ID in Commenda of the exemption certificate that's linked to this transaction. Used to mark a transaction as exempt. | | currency\_code | true | ISO-4217 currency string | Currency in which the transaction took place. | | exchange\_rate | false | number | Exchange rate for the currency if different from the corporation's base currency. | | exchange\_rate\_effective\_date | false | ISO-8601 date string | Date when the exchange rate was effective. | | parent\_invoice\_id | false | string | Optional (but recommended) for RETURN transactions. ID of the original sale transaction being returned. | | ship\_from\_address\_line\_1 | false | string | Address from which the shipment originated. | | ship\_from\_address\_line\_2 | false | string | Address from which the shipment originated. | | ship\_from\_address\_line\_3 | false | string | Address from which the shipment originated. | | ship\_from\_city | false | string | Address from which the shipment originated. | | ship\_from\_state\_code | false | ISO-3166-2 jurisdiction string valid in the origin country | Address from which the shipment originated. | | ship\_from\_zip | false | string (Valid postal code in origin country) | Address from which the shipment originated. | | ship\_from\_country\_code | false | ISO-3166 Country String | Address from which the shipment originated. | | ship\_to\_address\_line\_1 | false | string | Address to which the product is shipped or where the service is delivered. | | ship\_to\_address\_line\_2 [https://github.com/commenda-eng/product-and-api-docs/pull/73/conflict?name=engine%252Findirect-tax%252Ftransaction%252Fbulk-transactions.mdx\&ancestor\_oid=b4294b63c40ee5f14238c5993819b25b427f88a1\&base\_oid=e54b06895cc2f8a15d40e39ac3f42cd2882df35f\&head\_oid=d4fe0fc5a78c1f2ae643056bc6a64eb21bd5afb6](https://github.com/commenda-eng/product-and-api-docs/pull/73/conflict?name=engine%252Findirect-tax%252Ftransaction%252Fbulk-transactions.mdx\&ancestor_oid=b4294b63c40ee5f14238c5993819b25b427f88a1\&base_oid=e54b06895cc2f8a15d40e39ac3f42cd2882df35f\&head_oid=d4fe0fc5a78c1f2ae643056bc6a64eb21bd5afb6) | false | string | Address to which the product is shipped or where the service is delivered. | | ship\_to\_address\_line\_3 | false | string | Address to which the product is shipped or where the service is delivered. | | ship\_to\_city | false | string | Address to which the product is shipped or where the service is delivered. | | ship\_to\_state\_code | false | ISO-3166-2 jurisdiction string valid in the destination country | Address to which the product is shipped or where the service is delivered. | | ship\_to\_zip | false | string (Valid postal code in destination country) | Address to which the product is shipped or where the service is delivered. | | ship\_to\_country\_code | true | ISO-3166 Country String | Address to which the product is shipped or where the service is delivered. | | customer\_business\_identification\_number | false | string | The customer's tax or business registration number (e.g., VAT ID, EIN, GST number). Automatically populated when syncing from integrations that provide this data. | | marketplace | false | string | Marketplace name if the transaction is from a marketplace. | | tax\_remitter\_type | false | [Tax Remitter Type](#tax-remitter-type) | Indicates which party is responsible for remitting tax on the transaction. | | metadata | false | string (JSON) | Additional metadata for the transaction in JSON format. | ### Transaction Type Code One of the following values: * **SALE**: Standard sales transaction. Normally contains positive amounts but can include negative amounts for corrections. * **RETURN**: Return/refund transaction. All line items must have negative total amounts (price\_per\_unit \* quantity \< 0). * **PURCHASE**: Purchase transaction for input tax credit tracking (e.g. EU VAT, UK VAT). All line items must have negative total amounts. * **PURCHASE\_REFUND**: Refund of a purchase transaction. Auto-derived when creating a refund against a PURCHASE — do not set directly in bulk uploads. ### Special rules for RETURN and PURCHASE transactions When uploading RETURN or PURCHASE transactions via CSV, the following rules apply: 1. **Required fields:** * `transaction_type` must be set to "RETURN" or "PURCHASE" * `parent_invoice_id` is recommended but optional for RETURN transactions 2. **Amount sign rules:** * All line items must have negative total amounts * This can be achieved by either: * Setting negative `quantity` with positive `price_per_unit`, OR * Setting positive `quantity` with negative `price_per_unit` 3. **Line number matching:** * For line-level returns, the `line_number` should match the original invoice's line number ### Common Validation Errors in Bulk Upload | Error Code | Description | Solution | | ------------------------------- | ---------------------------------- | ---------------------------------------------------------------------- | | ERR\_INVALID\_RETURN\_AMOUNT | Return line has positive amount | Ensure price\_per\_unit \* quantity \< 0 | | ERR\_INVALID\_CORPORATION\_ID | Corporation ID doesn't match | Ensure corporation\_id matches the corporation specified in the upload | | ERR\_INVALID\_INVOICE\_ID | Missing or invalid invoice\_number | Provide a valid invoice\_number for each row | | ERR\_INVALID\_LINE\_ITEM\_COUNT | Too many line items per invoice | Reduce the number of line items per invoice | #### Process Code Indicates which operation is being performed (create transaction, update transaction, calculate tax, etc). Currently only transaction create is supported. Currently only `INSERT_TRANSACTION` is supported. #### Source Platform The method by which the transaction entered Commenda's system. Currently the following options are supported: `BIGCOMMERCE`, `BUSY`, `HUBSPOT`, `MEKARI_JURNAL`, `MS_DYNAMICS_365`, `MYOB_BUSINESS`, `NETSUITE`, `ODOO_ACCOUNTING`, `PAYPAL`, `PIPEDRIVE`, `QOYOD`, `QUICKBOOKS`, `QUICKBOOKS_SANDBOX`, `RAZORPAY`, `ROOTFI_SANDBOX`, `SAGE_CLOUD_ACCOUNTING`, `SAGE_ZA_CLOUD_ACCOUNTING`, `SHOPIFY`, `STRIPE`, `TALLY`, `WAFEQ`, `WAVE`, `WOOCOMMERCE`, `XERO`, `ZOHO_BOOKS`, `ZOHO_CRM`. #### Exemption Reason Reason why a purchaser is exempt from sales tax. Used to manually specify that a transaction is exempt because its purchaser is exempt. When this field is set, the transaction will not be considered for registration threshold tracking or for filings. Currently the following options are supported: `PURPOSE_RESALE`, `ENTITY_TYPE_NONPROFIT`, `GOVERNMENT`, `MANUFACTURER`, `AGRICULTURAL`, `EXEMPT_PRODUCT`, `OTHER`. #### Tax Remitter Type Indicates which party is responsible for remitting the tax on the transaction. This field is relevant for VAT and reverse-charge scenarios. Currently the following options are supported: * **SELLER**: The seller is responsible for collecting and remitting tax (default behavior). * **MARKETPLACE\_FACILITATOR**: A marketplace facilitator collects and remits the tax on behalf of the seller. * **BUYER**: The buyer is responsible for remitting the tax (reverse-charge mechanism, common in B2B VAT transactions). # Upload bulk transactions Source: https://docs.commenda.io/engine/indirect-tax/transaction/bulk-transactions-POST POST /transactions/bulk Submit a file of completed transactions for processing. The CSV file must include required fields for SALE, RETURN, and PURCHASE transactions. For RETURN and PURCHASE transactions, all line items must have negative total amounts. RETURN transactions should include parent_invoice_id when available. # Tax Transactions Source: https://docs.commenda.io/engine/indirect-tax/transaction/transaction Record transactions after they occur to remit and file the correct amount. ## Overview Commenda uses tax transactions to calculate the seller's tax obligations for filings and registration threshold tracking. If you are registered to pay taxes in a jurisdiction, the tax transactions will be automatically filed at the end of each filing period. ## Key Concepts ### Filing Status Each tax transaction has a `filing_status`. Possible values: * **UNCOMMITTED**: A transaction is initially created with the status `UNCOMMITTED`. This indicates that the transaction has been created but has not yet been included in a filing. It remains open for updates or deletion. * **IGNORED**: An `UNCOMMITTED` transaction can be marked as `IGNORED` to exclude it from the filing process. * **LOCKED**: After the filing period concludes, all `UNCOMMITTED` transactions that have not been marked as `IGNORED` are eventually transitioned to `LOCKED` status. In this state, they cannot be updated or deleted. Transactions are filed after being moved to the `LOCKED` state. ### Transaction id * The tax transaction id needs to be provided by the API user. * This allows for referential tracking and prevents deduplication in case the seller attempts to POST the same transaction twice. * The id does not need to be globally unique, but it must be unique for each seller. ### Transaction Types The system supports the following transaction types: | Type | Description | Use case | | ----------------- | ----------------------------- | ------------------------------------------------------------------ | | `SALE` | Standard sales transaction | New sales, corrections, re-invoicing | | `REFUND` | Refund of a previous sale | Full or partial refunds of SALE transactions | | `RETURN` | Legacy return type | Equivalent to REFUND, maintained for backward compatibility | | `PURCHASE` | Purchase transaction | Recording purchases for EU VAT / UK VAT input credit calculations | | `PURCHASE_REFUND` | Refund of a previous purchase | Auto-derived when creating a refund against a PURCHASE transaction | #### Sales transactions Use `SALE` for standard outgoing sales. You set `transaction_type` to `SALE` when creating the transaction. #### Refund transactions Use `REFUND` (or `RETURN`) for returns against a previous sale. Link the refund to the original sale via `parent_invoice_id`. #### Purchase transactions Use `PURCHASE` to record incoming purchase transactions. This is useful when you need to track input tax credits for EU VAT or UK VAT alongside your sales data. Purchase transactions do not affect sales-focused flows like registration threshold tracking, filing calculations, or daily sales summaries. They are stored separately for input credit calculations. #### Purchase refund transactions `PURCHASE_REFUND` is automatically assigned when you create a refund against a `PURCHASE` transaction using the refund endpoint. You do not set this type directly — it is derived from the parent transaction's type. #### Amount sign rules **For SALE transactions** * Line item amounts (`price_per_unit * quantity`) should normally be positive * Negative amounts are allowed for price corrections within an invoice (mixed with positive lines) or re-invoicing scenarios **For REFUND / RETURN transactions** * Line item amounts (`price_per_unit * quantity`) must be negative * Can be achieved through either: * Negative quantity with positive price, OR * Positive quantity with negative price * All line items in a REFUND transaction must have negative amounts **For PURCHASE transactions** * Line item amounts (`price_per_unit * quantity`) must be negative (similar to REFUND) **For PURCHASE\_REFUND transactions** * Line item amounts (`price_per_unit * quantity`) should be positive (similar to SALE) ### Filtering by transaction type When listing transactions, you can filter by type using the `types` query parameter (an array) or the legacy `type` parameter (a single value). If you do not provide a type filter, the API defaults to returning `SALE`, `REFUND`, and `RETURN` transactions only. `PURCHASE` and `PURCHASE_REFUND` transactions are excluded by default and must be explicitly requested. **Priority order:** `types` > `type` > default ```bash theme={null} # Return only purchase transactions GET /transactions?corporation_id=...&types=PURCHASE&types=PURCHASE_REFUND # Return all transaction types GET /transactions?corporation_id=...&types=SALE&types=REFUND&types=RETURN&types=PURCHASE&types=PURCHASE_REFUND ``` ### Tax remitter type The `tax_remitter_type` field indicates which party is responsible for remitting tax on the transaction. This is relevant for marketplace transactions and international VAT scenarios. | Value | Description | | ------------------------- | ----------------------------------------------------------------------------------------------------- | | `SELLER` | The seller collects and remits tax (default) | | `MARKETPLACE_FACILITATOR` | A marketplace facilitator collects and remits tax on behalf of the seller | | `BUYER` | The buyer is responsible for remitting tax (reverse-charge mechanism, common in B2B VAT transactions) | When a transaction is marked with `BUYER` as the tax remitter type, it indicates a reverse-charge scenario where the buyer self-assesses and remits the tax. This is common in cross-border B2B transactions within VAT jurisdictions. ### Bulk transactions See [Bulk Transactions](/engine/indirect-tax/transaction/bulk-transactions). ## Best practices ### Transaction type selection * Use `SALE` for new sales and correction scenarios with mixed positive/negative lines * Use `REFUND` for refunds of previous sales * Use `PURCHASE` for incoming purchases where you need to track input tax credits * Ensure all `REFUND` and `PURCHASE` transaction line items have negative amounts * Do not set `PURCHASE_REFUND` directly — create a refund against a `PURCHASE` transaction instead ### Amounts and signs * For re-invoicing corrections, use a `SALE` with mixed line signs * For refunds, use a `REFUND` with negative total line amounts * Be consistent within each transaction type ### Reference original transactions * Always link `REFUND` transactions to their original sales via `parent_invoice_id` * When creating a refund against a `PURCHASE`, the system automatically assigns `PURCHASE_REFUND` as the type * For line-level refunds, match `line_number` with the original invoice ### Date handling * Use `transacted_at` for the actual date of the return * Use `reporting_date_override` to control when the transaction appears in reports * Use `calculation_date_override` to apply historical tax rates from the original sale date # Delete transaction Source: https://docs.commenda.io/engine/indirect-tax/transaction/transaction-DELETE DELETE /transactions/{id} Deletes a transaction by its identifier This endpoint allows you to delete a transaction by its id. Once a filing for a state has taken place, the transaction's status will change to `LOCKED`. At that point, the transaction can no longer be deleted. Instead, you can create a refund transaction (coming soon) to notify our team that a refund has occurred, allowing us to adjust the sales tax paid in future filings. # List transactions Source: https://docs.commenda.io/engine/indirect-tax/transaction/transaction-GET GET /transactions List all transactions that match this query # Get transaction Source: https://docs.commenda.io/engine/indirect-tax/transaction/transaction-GET-ONE GET /transactions/{id} Retrieve one transaction by its identifier # Create a transaction Source: https://docs.commenda.io/engine/indirect-tax/transaction/transaction-POST POST /transactions Submit a completed transaction for processing and filing # US Sales Tax Calculation Source: https://docs.commenda.io/engine/indirect-tax/use-cases/us-sales-tax-calculation Learn how to calculate sales tax on transactions using Commenda's APIs. ## Overview Commenda helps you calculate sales tax on transactions using our APIs. This guide walks you through the complete workflow for US sales tax calculation, from initial setup to calculating taxes on your transactions. ## Prerequisites Before you can calculate sales tax, you need: 1. **Organization**: Contact Commenda to set up your organization. 2. **Corporation**: Create a corporation that reflects one real-world business entity. 3. **API Token**: Use your API token for authentication. ## Understanding US sales tax registration thresholds In the US, you are not required to collect sales tax from customers unless you exceed a physical or economic registration threshold in a state. Once you exceed a threshold (setting aside grace periods), you must: 1. Register in the state where you have exceeded the threshold 2. Collect sales tax from customers in that state 3. File and remit the collected taxes ## Workflow ### 1. Create a corporation Create a corporation using the [Create Corporation API](/engine/indirect-tax/corporation/corporation-POST). A corporation represents a real-world business entity (e.g., Commenda Technologies Inc.) that will be collecting and remitting taxes. * Provide your organization ID and corporation details * Save the corporation ID returned in the response for subsequent API calls * Each corporation should map to one legal entity in your business ### 2. Monitor registration threshold exposure Use the [Registration Thresholds API](/engine/indirect-tax/nexus/nexus-GET) to track your latest threshold exposure across states: * Monitor your transaction volume and revenue by state * Identify states where you are approaching or have exceeded registration thresholds * Determine which states require registration ### 3. Ingest transactions Use the [Transactions API](/engine/indirect-tax/transaction/transaction-POST) to submit your transaction data: * Submit completed transactions to track registration threshold progress * Include transaction details such as amounts, locations, and dates * Use [bulk import](/engine/indirect-tax/transaction/bulk-transactions-POST) for large transaction volumes ### 4. Register in exposed states Once you have exceeded the registration threshold in a state, create a registration using the [Create Registration API](/engine/indirect-tax/registrations/registrations-POST): * Provide your API token and corporation ID * Specify the state where you need to register * Include registration details such as effective date and tax ID If you attempt to calculate sales tax without a registration in a state, the calculation results will return zero. You must have an active registration to collect tax in that state. For sandbox environment testing, feel free to create a registration using the [Create Registration endpoint](/engine/indirect-tax/registrations/registrations-POST) rather than requesting a new one to perform tests. ### 5. Calculate sales tax After creating registrations in exposed states, use the [Calculate API](/engine/indirect-tax/calculate/calculate-POST) to calculate taxes on your transactions. #### Minimum required fields To calculate US sales tax, you must provide: * **Destination address**: The ship-to address of the invoice. The address is validated against the destination country's [address requirements](/engine/indirect-tax/address-requirements/address-requirements-GET). * **Calculation date**: The date of the transaction * **Invoice information**: Basic invoice details including: * Invoice total or subtotal * Line items with amounts and descriptions * Product tax codes (if applicable) See the [Calculate endpoint documentation](/engine/indirect-tax/calculate/calculate-POST) for complete field requirements and examples. Commenda also supports tax calculations for other countries beyond the US. Some countries require additional fields — for example, UK (`GB`) calculations require a ship-from address. See the [tax calculations overview](/engine/indirect-tax/calculate/calculate) for the full list of supported countries and their requirements. # Topics and Events Source: https://docs.commenda.io/engine/indirect-tax/webhooks/event ## Topics A topic represents a category of notifications that your webhook can subscribe to. It groups related events under a single, descriptive label. Topics allow you to organize and filter the types of updates you want to receive. ## Events An event is a notification that a specific action or change has occurred within Commenda’s system. Each event belongs to a topic and carries detailed information about the triggering action or change. All events share certain fields including the time they occur and the id of the affected organization. Events also have a field `data` which will be different for each topic. ```json theme={null} { "id": "b252d757-a286-4508-b538-41ad676e8305", "topic": "REGISTRATIONS.EXISTING.VALIDATION_SUCCEEDED", "triggered_at": 1727284490, "webhook_id": "2535af08-a139-4d0c-9827-1651e46dfbcf", "organization_id": "c2710df6-c6cf-4cd0-aa38-63faa44f16bc", "data": { // topic specific fields go here. }, "api_version": "v1.0" } ``` ## Topic Categories Commenda provides webhook notifications for events related to the following objects. This list is not exhaustive and more topic categories will be added soon. 1. Existing Registrations 2. New Registrations 3. Registration Thresholds 4. Indirect Tax Exposure 5. Filings 6. Exemption Certificates 7. Customs Duty ## Existing Registrations 1. #### `REGISTRATIONS.EXISTING.VALIDATION.SUCCEEDED` In order to allow Commenda to do automated sales tax and use tax filings for a corporation's existing registration, the registration needs to be validated by Commenda. To initiate the validation process the user can call the `POST /registrations/request-validation` endpoint. Validating a registration happens asynchronously and once the validation is successful this webhook is triggered. ```json theme={null} { "id": "b252d757-a286-4508-b538-41ad676e8305", "topic": "REGISTRATIONS.EXISTING.VALIDATION.SUCCEEDED", "triggered_at": 1727284490, "webhook_id": "2535af08-a139-4d0c-9827-1651e46dfbcf", "organization_id": "c2710df6-c6cf-4cd0-aa38-63faa44f16bc", "data": { "corporation_id": "a093d086-19e8-48c8-82d6-aba51f82eafc", "registration_id": "e3d97512-5415-4b3c-bcc9-f2d6ebf00d1b" }, "api_version": "v1.0" } ``` 2. #### `REGISTRATIONS.EXISTING.VALIDATION.FAILED` In some cases, a registration under validation will fail to pass our internal criteria. A non exhaustive list of failure cases is included below. More cases will be added over time. * `INPUTS.INVALID_CREDENTIALS` **Trigger:** To successfully file monthly sales tax for the customer, we need their tax portal credentials. If the entered credentials are wrong this error will be triggered. **Resolution:** The user needs to re-enter their credentials by hitting the `POST registrations/:id`. Once all the details are confirmed, you can call the `POST /registrations/request-validation` API endpoint again to request revalidation. * `INPUTS.INVALID_STATE_REGISTRATION_ID` **Trigger:** If the entered state registration ID is invalid, this error will be triggered. **Resolution:** The user needs to re-enter the invalid details by hitting the `POST registrations/:id`. Once all the details are confirmed, you can call the `POST /registrations/request-validation` API endpoint again to request revalidation. * `PAYMENTS.PORTAL_HAS_EXISTING_PENDING_PAYMENTS` **Trigger:** Every customer who is registered for sales tax needs to file and pay taxes to the state government. If during validation we find out that the customer has existing pending payments this error will be thrown. **Resolution:** The customer will need to make the payment for their pending filings. Once all the dues are cleared, you can call the `POST /registrations/request-validation` API endpoint again to request revalidation. * `OTHER` **Trigger:** Something unexpected went wrong. A human readable message on how to resolve the error and what went wrong will be attached. **Resolution:** The `data` interface of the event payload will contain a possible resolution for the error. ```json theme={null} { "id": "b252d757-a286-4508-b538-41ad676e8305", "topic": "REGISTRATIONS.EXISTING.VALIDATION.FAILED", "triggered_at": 1727284490, "webhook_id": "2535af08-a139-4d0c-9827-1651e46dfbcf", "organization_id": "c2710df6-c6cf-4cd0-aa38-63faa44f16bc", "data": { "corporation_id": "a093d086-19e8-48c8-82d6-aba51f82eafc", "registration_id": "e3d97512-5415-4b3c-bcc9-f2d6ebf00d1b", "errors" : [ { "type": "PORTAL.INVALID_CREDENTIALS", "doc_url": , "title": "Invalid credentials entered for California's sales tax portal.", "detail": "The client provided invalid login credentials for their California's sales tax portal (https://onlineservices.cdtfa.ca.gov/).". "resolution": "The user needs to re-enter their credentials by hitting the `POST registrations/:id`.Once all the details are confirmed, you can call the `POST /registrations/request-validation` API again and the validation process will start over." } ] }, "api_version": "v1.0" } ``` ## New Registrations 1. #### `REGISTRATIONS.NEW.SUCCEEDED` This webhook triggers when a new registration is successfully created. ````json theme={null} { "id": "b252d757-a286-4508-b538-41ad676e8305", "topic": "REGISTRATIONS.NEW.SUCCEEDED", "triggered_at": 1727284490, "webhook_id": "2535af08-a139-4d0c-9827-1651e46dfbcf", "organization_id": "c2710df6-c6cf-4cd0-aa38-63faa44f16bc", "data": { "corporation_id": "a093d086-19e8-48c8-82d6-aba51f82eafc", "registration_id": "e3d97512-5415-4b3c-bcc9-f2d6ebf00d1b" }, "api_version": "v1.0" } ``` 2. #### `REGISTRATIONS.NEW.INVALID` In the case of a missing value or a misconfigured field, Commenda will return an invalid state on the registration. In complex cases, we will also reach out to the customer directly to resolve registration difficulties as fast as possible. ```json { "id": "b252d757-a286-4508-b538-41ad676e8305", "topic": "REGISTRATIONS.NEW.INVALID", "triggered_at": 1727284490, "webhook_id": "2535af08-a139-4d0c-9827-1651e46dfbcf", "organization_id": "c2710df6-c6cf-4cd0-aa38-63faa44f16bc", "data": { "corporation_id": "a093d086-19e8-48c8-82d6-aba51f82eafc", "registration_id": "e3d97512-5415-4b3c-bcc9-f2d6ebf00d1b", "errors" : [ { "type": "PORTAL.INVALID_CREDENTIALS", "doc_url": , "title": "Invalid credentials entered for California's sales tax portal.", "detail": "The client provided invalid login credentials for their California's sales tax portal (https://onlineservices.cdtfa.ca.gov/).". "resolution": "The user needs to re-enter their credentials by hitting the `POST registrations/:id`.Once all the details are confirmed, you can call the `POST /registrations/request-validation` API again and the validation process will start over." } ] }, "api_version": "v1.0" } ```` ## Registration thresholds 1. #### `NEXUS.THRESHOLD.STATE.ALERT` Commenda internally tracks each corporation's progress toward registration thresholds. If a threshold is about to be exceeded in a jurisdiction where the customer is not registered, the customer will need to register in that jurisdiction. Registrations generally take some time, so it's better to register once you have reached around 80% of the threshold. This webhook is triggered everyday from the day when 80% threshold is crossed in a non registered state. ```json theme={null} { "id": "b252d757-a286-4508-b538-41ad676e8305", "topic": "NEXUS.THRESHOLD.STATE.ALERT", "triggered_at": 1727284490, "webhook_id": "2535af08-a139-4d0c-9827-1651e46dfbcf", "organization_id": "c2710df6-c6cf-4cd0-aa38-63faa44f16bc", "data": { "corporation_id": "a093d086-19e8-48c8-82d6-aba51f82eafc", "country": "US", "state": "AK", "nexus_rule": { "sales_threshold": 100000, "transaction_threshold": 200, "threshold_type": "SALES_OR_TRANSACTIONS", "evaluation_period_type": "PREVIOUS_CALENDAR_YEAR" }, "calculation": { "sales_exposure_percentage": 0.8, "transaction_exposure_percentage": 0.06, "total_sales": 80000, "total_transactions": 12 }, "is_nexus_breached": false, "date_of_breach": null }, "api_version": "v1.0" } ``` ## Indirect Tax Exposure 1. #### `INDIRECT_TAX.EXPOSURE.COMPUTED` Commenda continuously evaluates a corporation's transactions against jurisdiction-level nexus rules. When the set of jurisdictions where the corporation is exposed (i.e., has breached a registration threshold but does not yet have a covering active registration) changes, this webhook fires with the current full snapshot of exposed jurisdictions. Each item in `data.exposed[]` represents one jurisdiction that requires action. Use `recommended_registration_content_ids` to look up the corresponding V2 registration content via the [Available Registrations](/engine/indirect-tax/registrations/v2/content/available-registrations-POST) endpoint, then create a registration with [Create Registration V2](/engine/indirect-tax/registrations/v2/registrations-v2-POST) to clear the exposure. The payload contains the full current exposure set — treat each delivery as a snapshot rather than a delta. Jurisdictions that previously appeared but are absent from a later payload are no longer exposed. | Field | Type | Description | | ----------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | `data.corporation_id` | string | Corporation whose exposure was recomputed. | | `data.exposed[]` | array | Full snapshot of currently-exposed jurisdictions. May be empty. | | `data.exposed[].region_id` | string | Stable identifier for the exposed jurisdiction. | | `data.exposed[].jurisdiction_iso_code` | string | ISO code for the exposed jurisdiction (e.g., country or sub-jurisdiction code). | | `data.exposed[].jurisdiction_name` | string | Human-readable jurisdiction name (e.g., `"Germany"`, `"California"`). | | `data.exposed[].parent_jurisdiction_name` | string | Optional parent jurisdiction name (e.g., a trade bloc such as `"European Union"` for a member state). | | `data.exposed[].recommended_registration_content_ids` | array | Content IDs that, if registered for, would cover this exposure. Compare against active registrations' `registration_content_id` to determine coverage. | ```json theme={null} { "id": "b252d757-a286-4508-b538-41ad676e8305", "topic": "INDIRECT_TAX.EXPOSURE.COMPUTED", "triggered_at": 1727284490, "webhook_id": "2535af08-a139-4d0c-9827-1651e46dfbcf", "organization_id": "c2710df6-c6cf-4cd0-aa38-63faa44f16bc", "data": { "corporation_id": "a093d086-19e8-48c8-82d6-aba51f82eafc", "exposed": [ { "region_id": "REGION_DE", "jurisdiction_iso_code": "DE", "jurisdiction_name": "Germany", "parent_jurisdiction_name": "European Union", "recommended_registration_content_ids": [ "REG_COUNTRY_DE_3001_VAT", "REG_TRADEBLOC_EU_3000_UOSS_VAT" ] }, { "region_id": "REGION_US_CA", "jurisdiction_iso_code": "US-CA", "jurisdiction_name": "California", "parent_jurisdiction_name": "United States", "recommended_registration_content_ids": [ "REG_STATE_CEN_06_RST" ] } ] }, "api_version": "v1.0" } ``` ## Filings 1. #### `FILINGS.CREATED` Fires when one or more new sales tax filings are generated for the corporation (for example, when a new period opens). The payload includes the list of newly-created filings under `data.added_filings`. 2. #### `FILINGS.UPDATED` Fires when an existing filing is updated (for example, when its status changes, totals are recomputed, or it is filed). The payload includes the updated filings under `data.updated_filings`. Filings that have been removed are reported under `data.removed_filings`. ## Exemption Certificates 1. #### `EXEMPTION_CERTIFICATES.VERIFICATION.SUCCEEDED` This webhook is triggered when Commenda updates an exemption certificate's `verification_status` to `VERIFICATION_SUCCESS`. Tax calculation is based on active jurisdiction exemptions, effective dates, and expiration settings. A successful verification status does not by itself control tax treatment. ```json theme={null} { "id": "b252d757-a286-4508-b538-41ad676e8305", "topic": "EXEMPTION_CERTIFICATES.VERIFICATION.SUCCEEDED", "triggered_at": 1727284490, "webhook_id": "2535af08-a139-4d0c-9827-1651e46dfbcf", "organization_id": "c2710df6-c6cf-4cd0-aa38-63faa44f16bc", "data": { "corporation_id": "a093d086-19e8-48c8-82d6-aba51f82eafc", "certificate_id": "e3d97512-5415-4b3c-bcc9-f2d6ebf00d1b" }, "api_version": "v1.0" } ``` 2. #### `EXEMPTION_CERTIFICATES.VERIFICATION.FAILED` This webhook is triggered when Commenda updates an exemption certificate's `verification_status` to `VERIFICATION_FAILED`. When this status is set, the certificate's jurisdiction exemptions are deactivated. A non-exhaustive list of failure reasons is included below. More cases may be added over time. * `INPUTS.NAME_MISMATCH` **Trigger:** The customer name does not match the name on the exemption certificate. **Resolution:** Either update the name of the customer or upload the right exemption certificate. * `CERTIFICATE.CERTIFICATE_HAS_EXPIRED` **Trigger:** The expiration date mentioned on the exemption certificate has already passed and the certificate is no longer valid. **Resolution:** The customer will need to upload the latest version of the exemption certificate for the purchaser. * `CERTIFICATE.INVALID_TYPE_OR_FORMAT` **Trigger:** The certificate type is invalid for this customer. **Resolution:** The customer will need to upload the latest version of the exemption certificate for the purchaser. * `PURCHASER.MISSING_ADDRESS` **Trigger:** Some states, such as Texas, require the purchaser's address to be present on the exemption certificate. **Resolution:** Upload a newer exemption certificate that contains the purchaser's address. * `OTHER` **Trigger:** This covers edge cases. A human-readable message on what went wrong and how to resolve it will be attached. **Resolution:** The `data` interface of the event payload will contain a possible resolution for the error. ```json theme={null} { "id": "b252d757-a286-4508-b538-41ad676e8305", "topic": "EXEMPTION_CERTIFICATES.VERIFICATION.FAILED", "triggered_at": 1727284490, "webhook_id": "2535af08-a139-4d0c-9827-1651e46dfbcf", "organization_id": "c2710df6-c6cf-4cd0-aa38-63faa44f16bc", "data": { "corporation_id": "a093d086-19e8-48c8-82d6-aba51f82eafc", "certificate_id": "e3d97512-5415-4b3c-bcc9-f2d6ebf00d1b", "error": { "type": "INPUTS.NAME_MISMATCH", "doc_url": "https://docs.commenda.io/engine/indirect-tax/webhooks/event#exemption-certificates", "title": "Purchaser's name doesn't match on the Customer's model and Exemption certificate.", "detail": "The name of the customer doesn't match the name on the exemption certificate.", "resolution": "Either update the name of the customer or upload the right exemption certificate." } }, "api_version": "v1.0" } ``` 3. #### `EXEMPTION_CERTIFICATES.EXPIRATION` We send out a notification before an exemption certificate jurisdiction exemption expires, giving the customer notice that they need to upload a new one. **Trigger:** The expiration date on a jurisdiction exemption is approaching and the exemption will no longer be valid after that date. **Resolution:** The customer will need to upload the latest version of the exemption certificate for the purchaser. ```json theme={null} { "id": "b252d757-a286-4508-b538-41ad676e8305", "topic": "EXEMPTION_CERTIFICATES.EXPIRATION", "triggered_at": 1727284490, "webhook_id": "2535af08-a139-4d0c-9827-1651e46dfbcf", "organization_id": "c2710df6-c6cf-4cd0-aa38-63faa44f16bc", "data": { "corporation_id": "a093d086-19e8-48c8-82d6-aba51f82eafc", "customer_id": "f1e2d3c4-b5a6-7890-1234-56789abcdef0", "certificate_id": "e3d97512-5415-4b3c-bcc9-f2d6ebf00d1b", "end_date": "2025-02-27", "country": "US", "state": "TX" }, "api_version": "v1.0" } ``` ## Customs Duty 1. #### `CUSTOMS_DUTY.CUSTOMS_CODE.UPDATE` When products are shipped internationally, importing countries may charge customs duties on the shipment. The duty can be based on the price of the shipment, or on some other property like its weight or volume. When the required properties change, Commenda will notify users who have webhooks registered in order to inform them that they need to collect additional information about those products in order to calculate customs duty. ```json theme={null} { "id": "b252d757-a286-4508-b538-41ad676e8305", "topic": "EXEMPTION_CERTIFICATES.VERIFICATION.SUCCEEDED", "triggered_at": 1727284490, "webhook_id": "2535af08-a139-4d0c-9827-1651e46dfbcf", "organization_id": "c2710df6-c6cf-4cd0-aa38-63faa44f16bc", "data": { "customs_code": "1701.99.50.17", "destination_country": "US", "rules": [ { "description": "Other", "general_rate_of_duty": "35.74¢/kg", "units": ["COUNT", "KG"] } ] }, "api_version": "v1.0" } ``` # Webhooks Source: https://docs.commenda.io/engine/indirect-tax/webhooks/webhooks Receive real-time notifications about system events. ## Overview Some actions initated over Commenda's API can trigger long-running asynchronous processes. Users of Commenda's API can receive updates when those processes complete by registering webhooks with the `/webhooks` collection of endpoints. ## Concepts * **Topic**: A topic represents a category of notifications that your webhook can subscribe to. It groups related events under a single, descriptive label. Topics allow you to organize and filter the types of updates you want to receive. * **Event**: An event is a notification that a specific action or change has occurred within Commenda's system. Each event belongs to a topic and carries detailed information about the triggering action or change. ### How To Use Webhooks * **Topic Subscriptions:** Each webhook can listen to one or more topics, and multiple webhooks can subscribe to the same topic. * **Security Validation:** Webhook users must validate that their received messages were actually sent by Commenda. Commenda uses the **HMAC SHA256** scheme to validate webhook payloads. A `Commenda-X-Secret` header will be attached to every event payload. Learn more about HMAC SHA256 [here](https://webhooks.fyi/security/hmac). If you need any help with this, please contact the Commenda team. * **Event Objects:** Every time Commenda sends a request to your webhook URL, it includes an event object. You can read more about event objects [here](/engine/indirect-tax/webhooks/event). *** ## Getting Started 1. **Register Your Webhook** * Create a new webhook for a specific topic by making a `POST` request to the `/webhooks` endpoint. 2. **Test Your Webhook** * You can manually trigger a webhook call using the `POST /webhooks/test/trigger/:id` endpoint. More details are available [here](/engine/indirect-tax/webhooks/webhooks-TEST). 3. **You're All Set** * Once your webhook is registered, you'll start receiving updates for the topics you've subscribed to. 4. **Manage Your Webhook** * To update your webhook details, use the `POST /webhooks/:id` endpoint. * To delete a webhook, use the `DELETE /webhooks/:id` endpoint. # Delete webhook Source: https://docs.commenda.io/engine/indirect-tax/webhooks/webhooks-DELETE DELETE /webhooks/:id Delete an existing webhook. # Get webhook Source: https://docs.commenda.io/engine/indirect-tax/webhooks/webhooks-GET GET /webhooks/:id Get a webhook registered with Commenda. # List webhook Source: https://docs.commenda.io/engine/indirect-tax/webhooks/webhooks-LIST GET /webhooks Get a list of all webhooks registered with Commenda. # Create webhook Source: https://docs.commenda.io/engine/indirect-tax/webhooks/webhooks-POST POST /webhooks Register your webhook with Commenda. # Test webhook Source: https://docs.commenda.io/engine/indirect-tax/webhooks/webhooks-TEST POST /webhooks/test/trigger/:id Trigger a test against your webhook. # Update webhook Source: https://docs.commenda.io/engine/indirect-tax/webhooks/webhooks-UPDATE POST /webhooks/:id Update an existing webhook. # List customers Source: https://docs.commenda.io/engine/partner-api/customers-GET GET /partner/customers List customers visible to the authenticated partner API key. List customers visible to the authenticated partner API key. Use this endpoint when you need to recover a customer `id` before creating incorporations or managing customer-scoped Commenda OS resources. ```bash theme={null} curl --request GET \ --url 'https://api.prod.commenda.io/api/v1/partner/customers' \ --header 'x-api-key: YOUR_API_KEY' ``` ```json theme={null} { "customers": [ { "id": 77, "name": "Acme Holdings", "createdAt": "2026-04-20T19:35:00.000Z", "updatedAt": "2026-04-20T19:40:00.000Z" } ], "count": 1 } ``` # Create a customer Source: https://docs.commenda.io/engine/partner-api/customers-POST POST /partner/customers Create a customer record that scopes later Partner API calls. Create a customer record that scopes later Partner API calls. Save the returned `customer.id`. Use it as `{customerId}` when creating incorporations and when managing reusable Commenda OS resources such as people, business entities, and files. ```bash theme={null} curl --request POST \ --url 'https://api.prod.commenda.io/api/v1/partner/customers' \ --header 'x-api-key: YOUR_API_KEY' \ --header 'content-type: application/json' \ --data '{ "email": "founder@example.com", "name": "Acme Holdings" }' ``` ```json theme={null} { "customer": { "id": 77, "name": "Acme Holdings", "createdAt": "2026-04-20T19:35:00.000Z", "updatedAt": "2026-04-20T19:35:00.000Z" } } ``` # Partner API Source: https://docs.commenda.io/engine/partner-api/introduction Use Commenda's Partner API to create customers, manage entity data, start incorporations, upload files, track issues, and receive webhooks. The Partner API gives you a customer-scoped API surface for building incorporation and entity management flows inside your product. Base URL: ```text theme={null} https://api.prod.commenda.io/api/v1 ``` Pass your partner API key in the `x-api-key` header on every request. ```bash theme={null} curl --request GET \ --url 'https://api.prod.commenda.io/api/v1/partner/incorporation/jurisdiction-catalog' \ --header 'x-api-key: ' ``` ## What you can build Create the customer record that owns incorporations and reusable entity data. Collect requirements, submit intake, track status, and resolve correction requests. Create and reuse customer records such as business entities, people, files, documents, government identifiers, and registrations. Subscribe to events and verify signed webhook deliveries. ## Response conventions For the full naming, ID, casing, wrapper, validation, file, and error conventions, read [Partner API conventions](/engine/partner-api/conventions). * Customer-scoped endpoints only return resources visible to the partner firm associated with the API key. * List endpoints return an object containing the resource list and `count`. * Detail endpoints return an object containing the requested resource. * Requests without a valid `x-api-key` return `401`. * Requests for a customer or resource outside the partner firm's scope return `403` or `404`, depending on the endpoint boundary. ## Next steps Review the object model, IDs to save, and Commenda OS dependency before implementation. Follow the recommended end-to-end sequence for partner-led incorporations. # Delete webhook subscription Source: https://docs.commenda.io/engine/partner-webhooks/partner-webhook-subscriptions-DELETE DELETE /partner/webhook-subscriptions/{subscriptionId} Delete a webhook subscription for the authenticated partner. Deleted subscriptions stop receiving future webhook events. Deletes a webhook subscription for the authenticated partner. Deleted subscriptions stop receiving future webhook events. This endpoint returns `204 No Content` when deletion succeeds. # Get webhook subscription Source: https://docs.commenda.io/engine/partner-webhooks/partner-webhook-subscriptions-GET GET /partner/webhook-subscriptions/{subscriptionId} Retrieve one active webhook subscription for the authenticated partner. Responses include `secretPreview`, not the full signing secret. Retrieves one active webhook subscription for the authenticated partner. Read responses include `secretPreview`, not the full signing secret. If you lose the full secret returned at creation time, create a new subscription and delete the old one. # List webhook subscriptions Source: https://docs.commenda.io/engine/partner-webhooks/partner-webhook-subscriptions-LIST GET /partner/webhook-subscriptions List active webhook subscriptions for the authenticated partner. Responses include `secretPreview`, not the full signing secret. Lists active webhook subscriptions for the authenticated partner. List responses include `secretPreview`, not the full signing secret. # Create webhook subscription Source: https://docs.commenda.io/engine/partner-webhooks/partner-webhook-subscriptions-POST POST /partner/webhook-subscriptions Create a partner-level webhook subscription for incorporation issue events. The full signing secret is returned only in this create response. Creates a partner-level webhook subscription. The response includes the full `secret` exactly once. Store it securely and use it to verify webhook signatures. Later reads return only `secretPreview`. Webhook URLs must use HTTPS and must be reachable on public addresses. ## Example ```bash theme={null} curl --request POST \ --url 'https://api.prod.commenda.io/api/v1/partner/webhook-subscriptions' \ --header 'content-type: application/json' \ --header 'x-api-key: ' \ --data '{ "url": "https://partner.example.com/commenda/webhooks", "eventTypes": [ "INCORPORATION_ISSUE_CREATED", "INCORPORATION_ISSUE_RESOLVED" ] }' ``` # Partner webhooks Source: https://docs.commenda.io/engine/partner-webhooks/partner-webhooks Subscribe to partner API events. Partner webhooks notify your integration when important partner API events happen. Webhook subscriptions are partner-level resources under: ```text theme={null} https://api.prod.commenda.io/api/v1/partner/webhook-subscriptions ``` They are not scoped to a single customer or incorporation. A subscription receives events for your resources when its `eventTypes` includes the emitted event. ## Supported events | Event type | Trigger | | ------------------------------ | -------------------------------------------------------------- | | `INCORPORATION_ISSUE_CREATED` | Commenda creates a partner-visible issue for an incorporation. | | `INCORPORATION_ISSUE_RESOLVED` | Commenda resolves a partner-visible issue. | Commenda may add additional event types in future API updates. ## Delivery behavior Webhook delivery is asynchronous. Commenda retries failed deliveries. Your endpoint should: * Use HTTPS. * Be reachable on a public address. * Return a 2xx response within 10 seconds. * Treat events as at-least-once delivery and dedupe by `eventId`. Commenda stores only a bounded snippet of partner response bodies for delivery diagnostics. ## Signatures Each delivery includes these headers: | Header | Description | | ---------------------------- | ----------------------------------------------------- | | `Commenda-Webhook-Id` | Stable event id. Use this for idempotency. | | `Commenda-Webhook-Timestamp` | ISO timestamp generated for this delivery. | | `Commenda-Webhook-Signature` | HMAC SHA-256 signature in the form `v1=`. | The signature is computed with the subscription secret over: ```text theme={null} {Commenda-Webhook-Timestamp}.{raw_request_body} ``` The full secret is returned only when you create the subscription. Later reads return `secretPreview`. ## Incorporation issue payload ```json theme={null} { "eventId": "evt_incorporation_issue_created_issue_123", "eventType": "INCORPORATION_ISSUE_CREATED", "createdAt": "2026-04-25T21:00:00.000Z", "data": { "customerId": 77, "incorporationId": "0f9a8f5e-7f7c-4c1b-a60a-b1022f9d8c91", "issue": { "id": "issue_123", "code": "DOCUMENT_INVALID", "message": "The passport scan for Jane Founder is unreadable. Please upload a clearer scan.", "status": "ACTIVE", "scope": { "type": "PARTICIPANT_DOCUMENT", "participantId": "participant_123", "documentKind": "PASSPORT_SCAN", "fileId": 456 }, "createdAt": "2026-04-25T20:58:00.000Z", "updatedAt": "2026-04-25T20:59:00.000Z" } } } ``` ## Correction cycle semantics Resolved incorporation issues are not reopened. If Commenda needs another correction after a previous issue was resolved, a new issue is created and a new `INCORPORATION_ISSUE_CREATED` event is emitted. # API & Developer FAQ Source: https://docs.commenda.io/faq/api-and-developer-api Frequently asked questions about Commenda's API and developer resources Commenda offers six APIs: the Global Indirect Tax API (for tax calculation, registration, and transaction management), CommendaOS API (a global entity data modeling system), the Incorporation API, the Workflow Builder API, the Company Name Checker API, and the Address API. A full overview is available at[ API Introduction](https://docs.commenda.io/engine/api-introduction). CommendaOS is Commenda's global entity data modeling system — an API layer that exposes structured data about business entities, including government identifiers, registrations, locations, key persons, credentials, and documents. It is designed for software teams building products that need rich, structured entity data across multiple jurisdictions. Commenda APIs use API key-based authentication. API keys are passed in the request header (x-commenda-key) and are assigned specific roles that determine which endpoints they can access. Bearer token authentication is also supported for certain APIs. Full authentication documentation is available at[ API Introduction](https://docs.commenda.io/engine/api-introduction). Yes. Commenda's Indirect Tax API supports webhooks for event-driven integrations. Webhooks can be configured to fire on specific events, allowing downstream systems to react in real time when data changes in Commenda. The Workflow Builder is a Commenda API product that allows developers to define and execute custom multi-step workflows — for example, automating the sequence of steps involved in onboarding a new entity or completing a compliance filing. It uses a DSL (domain-specific language) to define workflow logic that can be triggered programmatically. # Billing & Pricing FAQ Source: https://docs.commenda.io/faq/billing Frequently asked questions about billing and pricing. Commenda offers different pricing plans depending on your needs. Services from the marketplace are priced individually. Contact your account manager or sales team for detailed pricing information. When you purchase a service from the marketplace, payment is processed through the checkout flow. Commenda accepts major payment methods. Yes. Invoices are generated for all marketplace purchases and subscription charges. You can access your billing history from the Settings section. Contact your account manager to discuss cancellation options for your plan or any active services. Yes. Many marketplace services offer different pricing variants based on the scope of work, entity type, or jurisdiction. You'll see all available options when browsing the marketplace. # Compliance FAQ Source: https://docs.commenda.io/faq/compliance-faq Frequently asked questions about Commenda's compliance platform Commenda's compliance calendar automatically tracks filing obligations for each of your entities based on their jurisdictions, entity types, and registration status. Upcoming deadlines appear in a centralized calendar view, and Commenda updates obligation schedules when regulatory deadlines change. This eliminates the need to manually track filing dates across multiple jurisdictions in spreadsheets.**What types of compliance obligations does Commenda track?** Commenda tracks a wide range of global compliance obligations, including: * Annual returns and annual reports * Corporate income tax filings * VAT / GST filings and registrations * Registered agent and registered office renewals * Business license renewals * Beneficial ownership (UBO) filings * Financial statement filings * Payroll and employer tax filings * Transfer pricing documentation deadlines * Entity renewals and government filings Commenda centralizes these obligations across jurisdictions with automated reminders and status tracking. Yes. Commenda's compliance calendar provides a consolidated view across all entities in your portfolio, so a Controller or Head of Tax can see every upcoming obligation across every jurisdiction from a single dashboard rather than checking each entity individually. Yes. Commenda sends automated alerts for upcoming compliance deadlines to help teams stay ahead of global obligations. Notifications are delivered through: * Email alerts * In-app notifications * Slack (optional integrations) * Shared compliance calendars These alerts cover upcoming filings, renewals, and other jurisdiction-specific compliance deadlines across all entities. Yes. Commenda supports recurring compliance tasks — obligations that repeat on a regular cadence (monthly, quarterly, annually) can be tracked and managed within the compliance calendar so they are never missed. If a compliance filing is rejected, Commenda updates the status to "Rejected" and keeps the item visible in the compliance calendar for remediation. Commenda also: * Sends alerts to relevant stakeholders * Flags the item as requiring action * Tracks remediation tasks and resubmission deadlines * Maintains an audit trail of status changes and updates This ensures rejected filings are quickly addressed and resubmitted. # Entity Management FAQ Source: https://docs.commenda.io/faq/entity-management Frequently asked questions about Commenda's entity management platform Entity management in Commenda is the central record of every legal entity a company operates — including its business information, registered addresses, key persons (directors, officers, shareholders, authorized signatories), ownership structure, bank accounts, government identifiers, and registrations. Commenda maintains this data in a structured, searchable format so finance teams always have an accurate, up-to-date view of their corporate structure. Commenda supports 3,500+ entity types across 100+ countries, including the most common business structures such as: * Corporations (C-Corp, S-Corp equivalents globally) * Limited Liability Companies (LLCs) * Partnerships (LP, LLP, and general partnerships) * Branch offices * Subsidiaries * Holding companies * Representative offices * Sole proprietorships This allows companies to manage their entire global entity structure in one platform. Yes. Commenda includes a corporate structure mapping feature that allows you to define ownership relationships between entities and visualize the full parent-subsidiary hierarchy of your corporate group. A key person in Commenda is any individual associated with a legal entity in an official capacity — such as a director, officer, shareholder, beneficial owner, or authorized signatory. Commenda tracks key person information at the entity level, including their role, tenure, and any associated documents. Yes. Commenda stores and tracks government-issued identifiers for each entity by jurisdiction, including: * EIN / Tax ID (U.S. and global equivalents) * VAT / GST registration numbers * Company registration numbers * Business license numbers * State / provincial tax IDs * Employer / payroll tax IDs * Import / export registration numbers (e.g., EORI) * Withholding tax IDs and other jurisdiction-specific identifiers All identifiers are centralized and tied to each entity for easy access, compliance tracking, and reporting. Commenda allows you to record and manage bank account details at the entity level, so financial information is stored alongside the rest of the entity's data rather than in separate spreadsheets or systems. Yes. Commenda supports team-based access with role-based permissions, so Controllers, finance staff, legal teams, and external advisors can each be given appropriate levels of access to entity data. Commenda computes UBOs automatically from the shareholdings recorded on each entity. A natural person becomes a UBO when their direct or indirect ownership crosses the threshold for the entity's incorporation country — typically 25% in the EU, US, UK, Canada, and Australia, and lower in many emerging markets. Commenda also supports: * **Control-only UBOs** — individuals who exercise significant control without holding equity * **Inherited UBOs** — UBOs of a corporate shareholder that propagate down to the entity below, with options to auto-inherit, opt out, or pick specific people See the [Ownership and beneficial owners](/product/entities/ownership) page for details. Yes. From the Ownership tab on any entity, click **Export** to download a PDF that includes the full shareholder register, every ultimate beneficial owner with their control type, and snapshot metadata suitable for sharing with banks, auditors, and regulators. # General FAQ Source: https://docs.commenda.io/faq/general Frequently asked questions about using Commenda. Commenda is an all-in-one entity management, tax, and compliance platform built for Controllers, CFOs, and Heads of Tax at multinational companies. Instead of coordinating multiple vendors and tracking obligations manually, finance teams use Commenda to manage their entire global compliance footprint from a single platform — covering legal entity data, compliance calendars, indirect tax, transfer pricing, and professional services. It also connects companies with advisors and service providers for professional services. Commenda is designed for finance leaders at multinational companies — primarily Controllers, CFOs, Heads of Tax, and their teams. It is particularly suited to companies that operate legal entities across multiple jurisdictions and find themselves managing a fragmented mix of spreadsheets, local advisors, and disconnected software tools to stay compliant. Commenda supports entity management and compliance tracking across 70+ countries. Yes. If you're involved with multiple companies, you can switch between them using the account switcher. Each company has its own set of entities, team members, and settings. You can reach Commenda support by using the in-app chat, emailing support, or contacting your account manager directly. Commenda integrates with QuickBooks, Xero, NetSuite, Zoho Books, Stripe, Shopify, WooCommerce, and more. See [Supported integrations](/integrations/supported-integrations) for the full list. When you add an entity and its jurisdiction details, Commenda automatically generates the applicable compliance obligations with their due dates. You can track each filing through its lifecycle and get reminders before deadlines. Commenda solves three core problems for multinational finance teams: (1) fragmented entity data spread across spreadsheets and multiple vendors, (2) compliance deadlines falling through the cracks when obligations are tracked manually or across disconnected systems, and (3) indirect tax complexity — particularly VAT, GST, and US sales tax — that is expensive and error-prone to manage through traditional methods. Yes. You can add entities manually through the platform or work with your Commenda account manager to bulk-import entity data from spreadsheets or other systems. The core difference is platform vs. people-dependent services. Commenda offers the same high-level expertise and compliance solutions as Big Four firms but at a fraction of the cost, with a more personalized approach and transparent, predictable pricing — unlike expensive hourly rates. Where traditional advisory models keep documentation and workflows siloed within the firm, Commenda gives internal teams cloud-based access to all documentation and workflows, enabling co-authoring, real-time visibility, and collaboration — without waiting on external delivery cycles. For jurisdictions that do require local expertise, Commenda provides global access to a network of local accounting, audit, advisory, and law firms that can be connected within days — so you get local knowledge without managing a fragmented roster of advisors yourself. Commenda is primarily a software platform — a SaaS product that gives finance teams direct visibility and control over their entity management and compliance obligations. It also offers a service marketplace where users can purchase professional services (such as incorporation, tax filing, and registered agent services) from vetted providers, making it a hybrid of software and services if needed. Commenda uses a modular, subscription-based pricing model that scales based on your entities, transaction volume, filings, and product modules. Instead of forcing companies into one bundled price, you pay for the capabilities you actually use. Commenda does not offer a free trial. However, you can request a free demo and a free exposure analysis to evaluate how Commenda would work for your business. # Indirect Tax FAQ Source: https://docs.commenda.io/faq/indirect-tax Frequently asked questions about Commenda's indirect tax platform (VAT, GST, Sales Tax) Commenda supports VAT (Value Added Tax), GST (Goods and Services Tax), and US sales tax. These cover the primary forms of indirect tax that multinational companies face when selling goods or services across international borders or US state lines. Commenda tracks registration thresholds by jurisdiction — the revenue or transaction volume levels at which a company becomes obligated to register for indirect tax. When transaction data is synced into Commenda, the platform monitors exposure against these thresholds and flags when a company is approaching or has exceeded a registration requirement. A registration threshold is the level of taxable sales or transactions in a jurisdiction above which a business is legally required to register for indirect tax (VAT, GST, or sales tax). Thresholds vary significantly by country and US state. Commenda tracks these thresholds and monitors company exposure against them so finance teams are alerted before a registration obligation is missed. Yes. Commenda's Indirect Tax API includes a tax calculation endpoint that computes the applicable sales tax, VAT, or GST for a given transaction based on the buyer's location, product type, and applicable exemptions. This can be integrated into billing or checkout systems via API. Nexus is the connection between a business and a US state that creates a sales tax obligation. A company has nexus in a state when it meets certain thresholds — either physical presence (an office, employee, or warehouse) or economic nexus (a certain volume of sales into that state). Commenda tracks nexus exposure across US states based on transaction data so companies know where they are obligated to collect and remit sales tax. Yes. Commenda manages exemption certificates — documents that allow certain buyers (e.g., resellers, non-profits) to purchase goods without paying sales tax. Commenda stores exemption certificates at the customer level, tracks their validity, and applies them to transactions to prevent over-collection of tax. Yes. Commenda is also built for digital businesses and SaaS companies selling globally, with full support for the jurisdiction-specific tax rules that apply to electronically supplied services, software subscriptions, and digital downloads. Yes. Commenda prepares, files, and remits your returns on your behalf — monthly, quarterly, or annually — across all registered jurisdictions, with no spreadsheets or manual uploads required. This covers both U.S. sales tax and international VAT filings. Commenda integrates with major accounting and e-commerce platforms to sync transaction data automatically. Supported platforms include Stripe, Shopify, Xero, QuickBooks, NetSuite, Zoho, and WooCommerce. This means transaction volume is monitored against registration thresholds without manual data entry. See the full list at[ Supported Integrations](https://docs.commenda.io/integrations/supported-integrations). Yes. Commenda supports bulk transaction import, allowing companies to upload historical transaction data to establish a baseline of prior tax exposure before going live with ongoing transaction syncing. # Integrations FAQ Source: https://docs.commenda.io/faq/integrations Frequently asked questions about Commenda's platform integrations. Commenda integrates with accounting and finance platforms (Xero, QuickBooks, NetSuite, Zoho), e-commerce platforms (Shopify, WooCommerce), and payment platforms (Stripe). A full integration capability matrix is available at[ Supported Integrations](https://docs.commenda.io/integrations/supported-integrations). Yes. Commenda integrates with both QuickBooks Online and QuickBooks Desktop. The integration syncs transaction data into Commenda for indirect tax threshold monitoring and calculation. Yes. Commenda integrates with NetSuite for transaction data syncing. Yes. Commenda integrates with Stripe to sync payment transaction data for indirect tax monitoring and calculation. Yes. Commenda integrates with Shopify to sync e-commerce transaction data. Yes. Commenda integrates with nearly every ERP, including NetSuite, QuickBooks Online, Xero, and Sage Intacct, syncing data bidirectionally in real time. Commenda connects via secure API and syncs transactions in real time — no custom development required.Invoices, transactions, and payments flow automatically from connected platforms with no manual uploads or data duplication.[ ](https://www.commenda.io/integration/qoyod/)For ERP connections, data syncs bidirectionally, meaning tax calculations and compliance data flow back into your source system as well. This connectivity is powered by a unified API layer — acquired from Integration Labs — that spans 30+ accounting, payments, and ecommerce platforms.[ ](https://www.commenda.io/blog/welcoming-integration-labs-to-commenda) # Security FAQ Source: https://docs.commenda.io/faq/security Frequently asked questions about data security and privacy. Commenda uses industry-standard security practices including: * Encryption in transit (TLS) and at rest * Role-based access control * Secure credential storage for sensitive information like tax portal passwords * Regular security audits Only people you've explicitly granted access to can see your data: * **Team members** with the roles you've assigned * **Advisor firms** linked to your company (only for assigned entities) * **Agent firms** working on your service requests (only for assigned work) * **Commenda admins** for platform support purposes Sensitive credentials (like tax portal usernames and passwords, bank account numbers, and government IDs) are encrypted using strong encryption before storage. They are only decrypted when needed by authorized users. Bank connections are handled through Plaid, a trusted financial data platform used by thousands of financial institutions. Commenda never stores your banking login credentials. The connection uses bank-level encryption. Yes. Commenda provides role-based access control with multiple roles (Admin, User, Accountant, Controller, Employee, Custom). You can restrict team members to specific entities and control what data they can view and edit. See [User roles](/introduction/user-roles). Documents can be set as private (specific team members), shared (your team and your advisor), or restricted based on the entity they belong to. File-level access control lists give you fine-grained control over who can view each document. Commenda staff who access the internal admin console must complete authenticator-app two-factor authentication (TOTP) on every sign-in: * Codes follow the RFC 6238 standard and are generated locally on the staff member's device using apps such as Google Authenticator, 1Password, or Authy. Codes are never delivered over SMS or email. * Each one-time code is valid for a single use within a short time window. Replays are rejected. * The shared secret is encrypted at rest, and only the staff member's authenticator app can produce a valid code. * A senior Commenda administrator can revoke a staff member's enrollment at any time. Revocation invalidates the staff member's active session immediately and forces them to re-enroll on their next sign-in. # Services & Marketplace FAQ Source: https://docs.commenda.io/faq/services-and-marketplace-faq Frequently asked questions about Commenda's services & marketplace Commenda's service marketplace offers professional services in eight categories: incorporation, tax filing, indirect tax, bookkeeping, compliance, transfer pricing, registered agent, and legal. Services are fulfilled by vetted provider firms available through the platform.**Can Commenda help incorporate a new legal entity?** Yes. Commenda's service marketplace includes incorporation services, and Commenda also provides an Incorporation API for software teams that want to embed entity incorporation into their own workflows or products. A registered agent is a designated individual or company authorized to receive legal documents and official government correspondence on behalf of a business entity in a given jurisdiction. Commenda's service marketplace includes registered agent services as a purchasable offering. When a user purchases a service through Commenda's marketplace, a service request is created. The service request tracks the status of the engagement — including documents required, tasks assigned, and progress toward completion — giving both the client and the service provider a shared view of the work. # Incorporating a new entity Source: https://docs.commenda.io/guides/incorporating-a-new-entity A walkthrough of the incorporation process through Commenda. This guide walks you through incorporating a brand new entity using Commenda's incorporation service. ## Before you begin Have the following ready: * **Entity name** — your preferred name (and 1-2 alternatives in case it's taken) * **Country and jurisdiction** — where you want to incorporate * **Entity type** — the legal structure (LLC, C-Corp, Pvt Ltd, etc.) * **Directors/officers** — names and details of the people who will serve as directors and officers * **Registered address** — an address in the incorporation jurisdiction * **Share structure** — for corporations, how many shares and what classes ## Step-by-step process Go to **Entities**, click **Add entity**, and select **Incorporate a new entity**. Choose the country and entity type. The wizard adapts to your chosen jurisdiction. Common fields include: * Proposed entity name * Business purpose * Registered address * Fiscal year end Enter the details for each director and officer. Depending on the country, you may need to provide: * Full legal name and date of birth * Nationality and residential address * Government ID information For corporations, specify: * Number of authorized shares * Share classes (common, preferred) * Par value and initial allocation Review all the information carefully. Once you submit, Commenda creates a service request and assigns it to an agent for processing. Follow the service request to monitor the incorporation status. You'll receive updates as the filing progresses. ## After incorporation Once the entity is successfully incorporated: * Commenda adds the entity to your account with all details populated * Commenda uploads formation documents to your document repository * Commenda generates compliance obligations for the new entity ## Timeline expectations | Country | Typical timeline | | -------------- | ----------------- | | United States | 1-5 business days | | Canada | 1-2 weeks | | United Kingdom | 1-3 business days | | Singapore | 1-2 business days | | India | 2-4 weeks | | UAE | 1-3 weeks | These are approximate timelines and may vary based on jurisdiction, entity type, and the completeness of your application. # Managing compliance Source: https://docs.commenda.io/guides/managing-compliance A practical guide to staying on top of compliance deadlines with Commenda. This guide covers best practices for managing your compliance obligations using Commenda. ## Your compliance workflow ### Weekly review Check your **Compliance Calendar** at least once a week: 1. Review items due in the next 30 days. 2. Check for items with **Action required** status. 3. Update statuses for any filings you've completed. ### When a filing is due Click on the item to see its details, requirements, and any attached documents. Make sure you have all the information and documents needed for the filing. Mark the item as **Under filing** so your team knows work is in progress. Either file the document yourself or create a service request for professional help. Once submitted, update the status and attach a copy of the filed document. ### Getting professional help If you need assistance with a filing: 1. Click **Create service request** from the compliance item. 2. Select the type of service needed. 3. A service request is created and assigned to a service provider. 4. Track the progress from the service request page. ## Tips for staying organized * **Set up recurring reviews** — block time each week to check your compliance calendar * **Delegate early** — create service requests well before deadlines * **Keep documents current** — upload filed documents immediately * **Monitor extensions** — if you file for an extension, track the new deadline carefully # Onboarding your company Source: https://docs.commenda.io/guides/onboarding-your-company A complete guide to setting up your company on Commenda for the first time. This guide walks you through the complete setup process when you first join Commenda. ## Before you start You'll need: * Your company's basic information (name, address, industry) * Details about your business entities (names, countries, entity types) * EINs or tax IDs for your entities (if available) * Key person information (directors, officers) ## Step 1: Create your account Visit [app.commenda.com](https://app.commenda.com) and sign up using your email address or Google account. Verify your email when prompted. ## Step 2: Company setup After signing in for the first time, you'll enter the onboarding flow: 1. **Company details** — enter your company name and basic information. 2. **Your profile** — provide your name and role. ## Step 3: Add your entities After the initial setup, add the business entities your company manages: Click **Add entity** and enter the entity's name, country of incorporation, entity type, and jurisdiction. For each entity, fill in the business information: EIN/tax ID, formation date, fiscal year end, and addresses. Add directors, officers, and signatories for each entity. Upload formation documents, bylaws, and other important files. Add all entities your company manages. You can always add more later. ## Step 4: Define corporate structure If your entities have parent-subsidiary or other relationships: 1. Go to an entity's **Ownership** tab. 2. Add relationships to other entities. 3. This is especially important if you'll be using transfer pricing features. ## Step 5: Review your compliance calendar With your entities set up, Commenda automatically generates compliance obligations. Go to **Compliance Calendar** to review upcoming deadlines. ## Step 6: Connect integrations (optional) To get the most out of Commenda, connect your accounting software for automatic transaction syncing. See [Supported integrations](/integrations/supported-integrations) for the full list. ## Step 7: Invite your team Add team members who need access. Go to **Settings**, invite members by email, and assign appropriate roles. ## What's next Configure indirect tax tracking for your entities. Learn how to stay on top of your filing deadlines. # Setting up indirect tax Source: https://docs.commenda.io/guides/setting-up-sales-tax A step-by-step guide to configuring indirect tax compliance in Commenda. This guide walks you through setting up indirect tax management for your entities in Commenda. ## Prerequisites * At least one entity added to your Commenda account * Business information filled in for the entity (EIN, addresses) * Knowledge of where you've exceeded indirect tax registration thresholds ## Step 1: Navigate to indirect tax Click **Indirect Tax** in the sidebar. If you have multiple entities, select the entity you want to configure. ## Step 2: Complete the onboarding flow The first time you access indirect tax for an entity, you'll go through a brief setup: 1. **Company details** — confirm or add details like your business type and NAICS code 2. **Tax configuration** — choose tax-inclusive or tax-exclusive pricing 3. **Locations** — add your business locations (these help determine registration thresholds) ## Step 3: Add your registrations Add each state or jurisdiction where you're registered for indirect tax: 1. Go to the **Registrations** tab. 2. Click **Add registration**. 3. Enter the jurisdiction, registration number, and filing frequency. 4. Add any local jurisdictions as needed. If you need to register in a new state, click **Request new registration** to start the process with Commenda's help. ## Step 4: Connect your transaction data ### Option A: Connect accounting software (recommended) 1. Click the integration option in your indirect tax settings. 2. Select your accounting platform. 3. Authorize the connection. 4. Commenda syncs your transaction data automatically. ### Option B: Upload CSV 1. Go to the **Transactions** tab. 2. Click **Upload CSV**. 3. Upload your transaction file and map the columns. ## Step 5: Classify your products Go to the **Products** tab and ensure your products are properly classified for tax purposes. ## Step 6: Set up exemption collection (if needed) If you have tax-exempt customers: 1. Go to the **Exemptions** tab. 2. Share your exemption portal link with customers. 3. Or manually upload exemption certificates. ## Step 7: Monitor filings Once set up, go to the **Filings** tab to see your upcoming filing deadlines. After initial setup, check the Indirect Tax section weekly to review new transactions and upcoming filing deadlines. # Working with your advisor Source: https://docs.commenda.io/guides/working-with-your-advisor How to collaborate with your accountant or advisory firm through Commenda. Commenda makes it easy to collaborate with your external accountant or advisory firm. This guide explains how the relationship works. ## Connecting your advisor Your accountant or advisory firm needs to have a Commenda account. Once they do: 1. Your Commenda account manager will link their firm to your company. 2. The advisor firm gets access to your entities and compliance data based on their assigned permissions. ## What your advisor can do Once connected, your advisor can: * **View your entities** — see business information, key persons, and registrations * **Manage compliance** — update filing statuses, track deadlines, and attach filed documents * **Access financial data** — view synced accounting data and transactions * **Deliver services** — handle filings, tax returns, and other compliance work on your behalf * **Communicate with you** — use built-in chat on service requests ## Communication Each service request includes a dedicated chat room where you can ask questions, share documents, and receive progress updates. You'll also receive notifications when your advisor updates a filing status or completes a task. ## Secure information requests Your advisor may send you **Secure information requests** to collect specific data or documents. These are structured forms that ensure all required information is provided. See [Secure information requests](/product/documents/secure-information-requests) for details. ## Multiple advisor firms If different advisor firms manage different entities or jurisdictions, Commenda supports linking multiple firms to your account. Each firm will only see the entities they're assigned to. # Accounting software integrations Source: https://docs.commenda.io/integrations/accounting/overview Connect your accounting platform to sync financial data and automate tax calculations. Commenda integrates with 20+ accounting platforms, allowing you to automatically sync transaction data, invoices, contacts, and chart of accounts. Once connected, Commenda uses this data to calculate indirect tax, generate financial reports, and keep your records up to date. ## Supported platforms | Platform | Category | Syncing | Tax calculation | | ---------------------- | ---------- | --------- | --------------- | | **QuickBooks Online** | Accounting | Supported | Supported | | **QuickBooks Desktop** | Accounting | Supported | Supported | | **Xero** | Accounting | Supported | Supported | | **NetSuite** | Accounting | Supported | Supported | | **Zoho Books** | Accounting | Supported | Supported | | **Wave** | Accounting | Supported | Limited | | **Sage** | Accounting | Supported | Limited | | **FreshBooks** | Accounting | Supported | Limited | | **Tally** | Accounting | Supported | Limited | | **Puzzle** | Accounting | Supported | Limited | | **Stripe** | Payments | Supported | Not supported | | **Shopify** | E-commerce | Supported | Not supported | | **Amazon** | E-commerce | Supported | Limited | | **WooCommerce** | E-commerce | Supported | Supported | Each platform supports different data models and sync configurations. See the individual integration pages for platform-specific details. ## How it works Navigate to the entity you want to connect. Look for the **Connect accounting software** option in your Indirect Tax or entity settings. Select the accounting platform you want to connect. You'll be redirected to your accounting platform's authorization page. Sign in and grant Commenda read access to the data models you want to sync. Choose what data to sync and how often. Options include transactions, invoices, contacts, chart of accounts, and journal entries. After authorization, Commenda starts pulling historical data from your platform. Depending on the volume of data, this can take anywhere from a few minutes to an hour. Commenda syncs your data on a configurable schedule. You can also trigger a manual resync at any time from the dashboard. ## Data models Depending on your platform and use case, Commenda can sync the following data: ### Transactions * **Invoices** — sales invoices with line items, tax amounts, and customer details * **Bills** — purchase bills and vendor invoices * **Invoice credit notes** — credits issued against invoices * **Bill credit notes** — credits received from vendors * **Cash refunds** — refund transactions ### Contacts * **Customers** — customer profiles with billing and shipping addresses * **Vendors** — vendor and supplier contact information ### Financial statements * **Income statement** — revenue, expenses, and net income over a specified period * **Balance sheet** — assets, liabilities, and equity at a point in time * **Cash flow statement** — cash inflows and outflows over a specified period ### Chart of accounts * **Accounts** — your full chart of accounts, used for mapping transactions to the correct tax categories ## Sync configuration When you set up a connection, you configure how frequently Commenda syncs each data model: | Setting | Description | | ------------------ | ----------------------------------------------------------- | | **Sync frequency** | How often to pull new data (hourly, daily, weekly, monthly) | | **Sync from date** | How far back to pull historical data | | **Permissions** | What operations Commenda can perform (read, create, update) | | **Enabled** | Whether syncing is active for a specific data model | You can update these settings at any time from the integration settings page. ## Integration settings Each connected platform has a settings page where you can manage: * **Sync enabled** — toggle data syncing on or off * **Tax calculation enabled** — toggle automatic tax calculations on synced transactions * **Tax calculation start date** — the date from which Commenda should start calculating taxes on your transactions * **Platform-specific settings** — some platforms have additional configuration options (for example, Stripe supports a fallback to payment method address for tax jurisdiction resolution) ## Sync status You can check the current sync status for each connected platform. The status tells you: * Whether a sync is **in progress**, **completed**, or **failed** * When the last successful sync occurred * Which use case the connection is configured for If a sync fails, you can trigger a manual resync from the dashboard. Use the **full resync** option to re-pull all data from the configured start date. Confirm your accounting data is up to date before relying on synced data for tax filings. Commenda syncs data periodically, so very recent transactions may not appear immediately. ## Disconnecting an integration You can disconnect an integration at any time. Disconnecting stops all data syncing and tax calculations for that platform. Your previously synced data remains available in Commenda, but Commenda no longer pulls new data. To permanently remove the connection and all associated configuration, use the delete option instead of disconnect. ## Next steps Connect QuickBooks for accounting data sync and tax calculation Connect Xero for accounting data sync and tax calculation Connect Zoho Books for accounting data sync and tax calculation Connect Stripe for payment data syncing # NetSuite Source: https://docs.commenda.io/integrations/netsuite/overview Connect NetSuite to sync accounting data and automate indirect tax calculations ## Overview The NetSuite integration connects your Oracle NetSuite account to Commenda for automatic transaction syncing and indirect tax calculation. Commenda pulls your receivables (invoices, cash sales, cash refunds), payables (bills and bill credit notes), contacts, and items, then calculates and applies the correct indirect tax on your NetSuite sales documents. ## Supported features | Feature | Status | | -------------------------------------------------------- | --------- | | Receivables syncing (invoices, cash sales, cash refunds) | Supported | | Payables syncing (bills, bill credit notes) | Supported | | Tax calculation on sales documents | Supported | | Real-time webhooks | Supported | ## Data models Commenda syncs the following data from NetSuite: ### Receivables * **Invoices** — sales invoices with line items and addresses * **Cash sales** — point-of-sale and cash transactions (unique to NetSuite) * **Cash refunds** — refund transactions ### Payables * **Bills** — vendor bills with line items, vendor details, and tax amounts * **Bill credit notes** — credits received from vendors against previously issued bills ### Reference data * **Contacts** — customer and vendor profiles with billing and shipping addresses * **Items** — your product and service catalog Tax calculation also supports **estimates** and **sales orders** in addition to the synced data models. Tax calculation runs on receivable-side documents only — bills and bill credit notes are ingested as-is for reporting and reconciliation. ## Accounts payable Commenda ingests NetSuite **Bills** and **Bill Credit Notes** into the same unified transaction model used for receivables, so you can report on spend, reconcile vendor activity, and surface purchase data alongside your sales data. Key behaviors: * **Vendor resolution.** Vendors on bills are resolved from NetSuite's vendor records (separate from customer records). Commenda fetches vendor details — including billing and shipping addresses — via a passthrough call to NetSuite using the platform vendor ID on each bill. * **Amount handling.** Bill amounts are ingested with signs that mirror NetSuite's conventions: * **Bills** — tax amounts are normalized so credits and debits reconcile correctly across the unified model. * **Bill credit notes** — line amounts, quantities, and unit prices are negated so credit notes offset the original bill. * **Discount line items.** Document-level discount lines are detected, excluded from the line-item list, and prorated across the remaining product lines so per-line net amounts stay accurate. * **Address resolution.** Vendor billing and shipping addresses are resolved from the bill payload first, then fall back to the vendor record. NetSuite's receivable-only SuiteScript flow is skipped for payables, so no plugin configuration is required for bills. * **No tax calculation on bills.** Commenda does not calculate or write tax back to bills or bill credit notes — these documents are read-only from a tax perspective and used for ingestion and reporting. Bills and bill credit notes are enabled automatically when you connect NetSuite. You do not need to change any plugin settings or SuiteScript deployments to sync payables. ## How tax calculation works When you create or update a document in NetSuite, Commenda automatically: 1. Receives a webhook notification 2. Fetches the full document details including addresses 3. Resolves the shipping address from the document or the associated customer record 4. Calculates the applicable indirect tax 5. Updates the document with the correct tax amounts ## Address resolution NetSuite uses a two-tier address approach: 1. **Document-level addresses** — Commenda first checks for shipping and billing addresses directly on the invoice or transaction 2. **Customer-level addresses** — if no acceptable document-level address is found, Commenda looks up the customer's default shipping and billing addresses The priority order is: 1. Document shipping address 2. Customer default shipping address 3. Document billing address 4. Customer default billing address Addresses where only the country field is populated are considered incomplete and skipped. This prevents incorrect tax jurisdiction assignments from auto-populated country-only addresses. ## Prerequisites Before connecting NetSuite, ensure the following: * You have administrator access to your NetSuite account * The **Commenda SuiteScript plugin** is installed in your NetSuite account — this plugin enables Commenda to query customer address data The NetSuite integration requires a custom SuiteScript deployment for full functionality. Contact your Commenda account team for installation instructions. ## Connecting NetSuite Work with your Commenda account team to install the required SuiteScript plugin in your NetSuite account. This enables Commenda to access customer address data for tax jurisdiction resolution. From your Commenda dashboard, navigate to integrations and select **NetSuite**. Commenda generates a secure connection link. Click the connection link to authorize Commenda to access your NetSuite data. Choose which data models to sync, set the sync frequency, and specify how far back to pull historical data. After authorization, Commenda begins the initial data sync. Check the sync status on your dashboard to confirm data is flowing. Before going live, run through the plugin checklist to verify the bundle is set up correctly. Repeat it after any bundle update or new state registration. ## Known behaviors * **Cash sales** is a NetSuite-specific transaction type not found in other integrations. * Commenda only skips **draft** status transactions — NetSuite is more permissive than other platforms, with statuses like deposited, not deposited, and unknown all eligible for processing. * Customer IDs in NetSuite use a `customer_` prefix internally; vendor IDs on bills and bill credit notes use a `vendor_` prefix. Commenda handles both automatically. * Receivables and payables flow through separate resolution paths — customer-side address lookups use the Commenda SuiteScript plugin, while vendor-side lookups use NetSuite passthrough calls. ## Next steps * [NetSuite Plugin Checklist](/integrations/netsuite/plugin-checklist) * [Accounting data integrations overview](/integrations/accounting/overview) * [Supported integrations](/integrations/supported-integrations) # NetSuite plugin checklist Source: https://docs.commenda.io/integrations/netsuite/plugin-checklist Confirm tax is calculating correctly after the Commenda bundle is installed or updated in your NetSuite account Run this checklist every time the Commenda bundle is installed or updated in your NetSuite account. It ends with real test transactions, which is the only reliable way to know tax is being applied. Work through the steps in order. If any step does not come out the way it says it should, contact us before going live rather than continuing. ## The checklist Go to **Setup → Company → Enable Features**. Under **SuiteCloud**, enable Token-Based Authentication, OAuth 2.0, REST Web Services, Client SuiteScript, and Server SuiteScript. All five are enabled before the bundle is installed. If any are off, the install fails with a generic "An unexpected error has occurred" that gives no indication of the cause. Add every registration you already hold to the Commenda app. Each state or region you are registered in appears in your account. Transactions in a state you have not added come out untaxed, so add them all before your first taxed transaction. Create an invoice, a sales order, a cash sale, a credit memo, and an estimate, each for an address where you are registered. All five carry the correct tax. If tax comes out as 0.00, or one type behaves differently from the others, stop and send us the record number before going live. If you sell to tax-exempt customers, create a transaction for one who has a certificate on file. The transaction completes with no tax. If tax is still applied, contact us before you go live. Installing the bundle creates a single tax code named **Commenda**. You do not need to create tax codes or list your jurisdictions, as that happens automatically. A tax code named **Commenda** appears in your NetSuite tax code list. If it is not there, the bundle install has not completed. Contact us before creating any further transactions. Commenda works with NetSuite's legacy tax engine, so if your account runs SuiteTax, tell us before the bundle is installed. The tax calculation setting lives in the bundle inside NetSuite, not in your Commenda dashboard. Check there if you need to confirm whether calculation is switched on. ## Next steps Every step passed, so you are ready to go live. Run this checklist again after any bundle update or new registration. If a step does not behave the way it is described here, send us the record number and we will take it from there. How the integration connects, what it syncs, and how tax calculation works Every platform Commenda connects to # QuickBooks Source: https://docs.commenda.io/integrations/quickbooks/overview Connect QuickBooks to sync accounting data and automate indirect tax calculations ## Overview The QuickBooks integration connects your QuickBooks Online account to Commenda for automatic transaction syncing and real-time indirect tax calculation. Once connected, Commenda pulls your invoices, credit notes, contacts, and items, then calculates and applies indirect tax directly on your QuickBooks documents. ## Supported features | Feature | Status | | ------------------- | --------- | | Transaction syncing | Supported | | Tax calculation | Supported | | Real-time webhooks | Supported | ## Data models Commenda syncs the following data from QuickBooks: * **Invoices** — sales invoices with line items, amounts, and addresses * **Invoice credit notes** — credits issued against invoices * **Cash refunds** — refund transactions * **Contacts** — customer profiles with billing and shipping addresses * **Items** — your product and service catalog ## How tax calculation works When you create or update an invoice in QuickBooks, Commenda automatically: 1. Receives a webhook notification from QuickBooks 2. Fetches the full invoice details including shipping address 3. Calculates the applicable indirect tax based on the shipping address 4. Updates the invoice in QuickBooks with the correct tax amounts Commenda adds a tax line item labeled **"Tax calculated by Commenda"** to each processed invoice. If a calculation error occurs, an error indicator is added to the invoice's private notes. Tax calculation runs on invoices, credit notes, cash refunds, estimates, sales orders, and cash sales. ## Address resolution Commenda determines the tax jurisdiction using the **shipping address on the document**. QuickBooks provides the shipping address (`ShipAddr`) directly on each invoice, so no additional lookups are needed. If the shipping address is missing or incomplete, the transaction may not be eligible for tax calculation. ## Connecting QuickBooks From your Commenda dashboard, navigate to integrations and select **QuickBooks**. Commenda generates a secure connection link. Click the connection link to open the QuickBooks authorization page. Sign in to your QuickBooks account and grant Commenda access to your accounting data. Choose which data models to sync, set the sync frequency, and specify how far back to pull historical data. After authorization, Commenda begins the initial data sync. Check the sync status on your dashboard to confirm data is flowing. QuickBooks Sandbox accounts are also supported for testing your integration before going live. ## Known behaviors * Commenda only processes **accounts receivable** invoices for tax calculation * Commenda skips invoices with a **draft** or **unknown** status * Commenda processes invoices that are **paid**, **partially paid**, **submitted**, **void**, or **overdue** for tax calculation * QuickBooks private notes have a character limit, so error messages may be truncated ## Next steps * [Accounting data integrations overview](/integrations/accounting/overview) * [Supported integrations](/integrations/supported-integrations) # Shopify Source: https://docs.commenda.io/integrations/shopify/overview Connect Shopify to sync e-commerce transaction data ## Overview The Shopify integration connects your Shopify store to Commenda for automatic e-commerce data syncing. Commenda pulls your transactions, products, and customers to provide a unified view of your sales data for tax compliance. ## Supported features | Feature | Status | | ------------------- | --------- | | Transaction syncing | Supported | | Tax calculation | Supported | | Real-time webhooks | Supported | ## Data models Commenda syncs the following data from Shopify: * **Transactions** — order and transaction data including line items, amounts, and fulfillment details * **Products** — your product catalog * **Customers** — customer profiles with addresses ## How tax calculation works When a transaction is created or updated in Shopify, Commenda receives the event through its unified webhook pipeline. Commenda fetches the full order details associated with the transaction to extract address information and calculates the applicable indirect tax. ## Address resolution Shopify transaction data does not include complete address information directly. Commenda resolves addresses by fetching the associated **order data**, which contains: 1. **Shipping address** — the order's shipping address 2. **Billing address** — the order's billing address (used as fallback) The shipping address takes priority for tax jurisdiction determination. ## Connecting Shopify From your Commenda dashboard, navigate to integrations and select **Shopify**. Commenda generates a secure connection link. Click the connection link to authorize Commenda to access your Shopify store data. Choose which data models to sync, set the sync frequency, and specify how far back to pull historical data. After authorization, Commenda begins the initial data sync. Check the sync status on your dashboard to confirm data is flowing. ## Known behaviors * Transactions with a `null` status are still processed (some Shopify transactions may not have an explicit status) * Address information is fetched from the associated order, not from the transaction itself ## Next steps * [Accounting data integrations overview](/integrations/accounting/overview) * [Supported integrations](/integrations/supported-integrations) # Stripe Source: https://docs.commenda.io/integrations/stripe/overview Connect Stripe to sync payment data and automate indirect tax calculations ## Overview The Stripe integration connects your Stripe account to Commenda for automatic payment data syncing and real-time indirect tax calculation on invoices. Commenda pulls your invoices, customers, products, and credit notes, then calculates and applies the correct tax rates directly on your Stripe invoices. ## Supported features | Feature | Status | | ------------------- | --------- | | Transaction syncing | Supported | | Tax calculation | Supported | | Real-time webhooks | Supported | ## Data models Commenda syncs the following data from Stripe: * **Invoices** — Stripe invoices with line items and customer details * **Credit notes** — credits issued against invoices * **Customers** — customer profiles with billing and shipping addresses * **Products** — your product catalog * **Items** — price and subscription items ## How tax calculation works When a draft invoice is created or updated in Stripe, Commenda automatically: 1. Receives a webhook notification from Stripe 2. Fetches the full invoice details and customer information 3. Resolves the applicable tax jurisdiction from the available addresses 4. Calculates the correct indirect tax 5. Creates or updates tax rates in your Stripe account and applies them to each line item Tax calculation only runs on **draft** invoices. Once an invoice is finalized or paid, it is no longer modified. If Stripe's built-in `automatic_tax` feature is enabled on an invoice, Commenda disables it to prevent conflicts. ## Address resolution Stripe supports multiple address sources. Commenda checks them in the following priority order: 1. **Invoice shipping address** — the shipping details set directly on the invoice 2. **Customer shipping address** (at finalization) — the customer's shipping address captured when the invoice was created 3. **Customer shipping address** (current) — the customer's current shipping address 4. **Invoice billing address** (at finalization) — the customer's billing address captured when the invoice was created 5. **Customer billing address** (current) — the customer's current billing address ### Fallback to payment method address For paid invoices, you can enable an additional fallback that extracts the billing address from the payment method used to pay the invoice. This is useful when customers don't have addresses on file but provide billing details during checkout. You can enable this from your integration settings under **Platform settings** > **Fallback to payment method address**. ## Connecting Stripe From your Commenda dashboard, navigate to integrations and select **Stripe**. Commenda generates a secure connection link. Click the connection link to open Stripe's authorization page. Sign in and grant Commenda access to your account data. Choose which data models to sync, set the sync frequency, and specify how far back to pull historical data. After authorization, Commenda begins the initial data sync. Check the sync status on your dashboard to confirm data is flowing. ## Platform-specific settings The Stripe integration has additional settings you can configure: | Setting | Description | | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | **Fallback to payment method address** | When enabled, Commenda uses the billing address from the payment method as a last resort for tax jurisdiction resolution on paid invoices | ## Known behaviors * Only **draft** invoices are eligible for tax calculation * Stripe amounts are in the smallest currency unit (cents for USD) and are converted automatically * Commenda creates tax rates dynamically in your Stripe account as it encounters new rates * Credit notes use the customer's address since they don't carry their own address fields ## Next steps * [Accounting data integrations overview](/integrations/accounting/overview) * [Supported integrations](/integrations/supported-integrations) # Supported integrations Source: https://docs.commenda.io/integrations/supported-integrations A complete list of platforms Commenda integrates with. Commenda integrates with accounting software, e-commerce platforms, payment processors, and bank accounts to automatically sync your financial data. ## Accounting and finance | Platform | Syncing | Tax calculation | Notes | | ---------------------- | ------- | --------------- | ----------------------------------------- | | **QuickBooks Online** | Yes | Yes | Full transaction and invoice syncing | | **QuickBooks Desktop** | Yes | Yes | Via web connector | | **Xero** | Yes | Yes | Full transaction and invoice syncing | | **NetSuite** | Yes | Yes | Calculation requires plugin installation | | **Zoho Books** | Yes | Yes | Calculation requires manual webhook setup | | **Wave** | Yes | Limited | Transaction syncing | | **Sage** | Yes | Limited | Transaction syncing | | **FreshBooks** | Yes | Limited | Invoice and transaction syncing | | **Tally** | Yes | Limited | Transaction syncing | | **Puzzle** | Yes | Limited | Transaction and accounting syncing | ## E-commerce | Platform | Syncing | Tax calculation | Notes | | --------------- | ------- | --------------- | -------------------------------------------- | | **Shopify** | Yes | No | Order and transaction syncing only | | **WooCommerce** | Yes | Yes | Plugin supports both syncing and calculation | | **Amazon** | Yes | Limited | Transaction syncing | ## Payments | Platform | Syncing | Tax calculation | Notes | | ---------- | ------- | --------------- | --------------------------- | | **Stripe** | Yes | No | Payment and invoice syncing | ## Banking | Platform | Description | | --------- | ------------------------------------------------------------------------------------------------------- | | **Plaid** | Bank account connection for balance and transaction data. Supports thousands of financial institutions. | ## Other integrations | Platform | Purpose | | ------------ | -------------------------------- | | **DocuSign** | Electronic document signing | | **Cal.com** | Meeting scheduling with advisors | ## Setting up an integration For step-by-step setup instructions, see: * [Accounting software setup](/integrations/accounting/overview) * Individual integration pages for platform-specific details (Stripe, Shopify, Xero, etc.) # WooCommerce plugin checklist Source: https://docs.commenda.io/integrations/woocommerce/plugin-checklist Confirm tax is calculating correctly after the Commenda plugin is installed or updated on your WooCommerce store Run this checklist every time the Commenda plugin is installed or updated on your WooCommerce store. It takes about fifteen minutes and ends with a real test order, which is the only reliable way to know tax is being applied. Work through the steps in order. If any step does not come out the way it says it should, contact us before going live rather than continuing. ## The checklist Go to **WooCommerce → Settings → General** and tick **Enable taxes**. A **Tax** tab appears in your WooCommerce settings. Leave this off and Commenda still calculates the tax, but WooCommerce discards the result and every order ships untaxed. This is the most common cause of missing tax, and it can run for months with nothing else looking wrong. Add every registration you already hold to the Commenda app. Each state or region you are registered in appears in your account. Anything missing here ships untaxed, so add them all before your first taxed order. Place a test order in your store, shipping to an address where you are registered. Tax is added at checkout and appears as a tax line on the completed order. If tax comes out as 0.00, stop and contact us before going live. Do not keep placing orders. Add and remove a few items from the cart, then go through to checkout. Tax appears at checkout, and the cart responds as quickly as it did before. Tell us if adding items feels slower than it used to. If you sell to tax-exempt customers, place an order for one who has a certificate on file. The order completes with no tax. If tax is still applied, contact us before you go live. Fees added to an order are not currently included in the tax calculation. Tell us if you use fee lines and we will handle it for your account. ## Next steps Every step passed, so you are ready to go live. Run this checklist again after any WooCommerce update, plugin update, or new registration. If a step does not behave the way it is described here, send us the order number and we will take it from there. How the integration connects, what it syncs, and how to set it up Every platform Commenda connects to # WooCommerce Source: https://docs.commenda.io/integrations/woocommerce/setup Learn how Rootfi integrates with WooCommerce to fetch e-commerce data ## Overview Rootfi's WooCommerce integration enables you to seamlessly fetch and synchronize e-commerce data from WooCommerce stores. This integration provides access to orders, products, customers, inventory, and other critical business data. ## How it works The WooCommerce integration connects to your WooCommerce store using the WooCommerce REST API. Once authenticated, Rootfi can fetch data from your store and keep it synchronized in real-time through webhooks. ### Architecture 1. **Authentication**: Secure connection using WooCommerce API keys 2. **Data fetching**: Periodic synchronization of store data via REST API 3. **Real-time updates**: Webhook notifications for immediate data changes 4. **Data normalization**: Standardized data format across all integrations ## Authentication ### Prerequisites * WooCommerce store with REST API enabled * Admin access to generate API credentials * HTTPS enabled on your store (required for API access) ### Connection process 1. Navigate to your WooCommerce admin dashboard 2. Go to **WooCommerce** > **Settings** > **Advanced** > **REST API** 3. Click **Add key** to generate new API credentials 4. Set the following: * **Description**: Rootfi Integration * **User**: Select an admin user * **Permissions**: Read/Write 5. Copy the generated **Consumer Key** and **Consumer Secret** 6. In Rootfi, provide: * Store URL * Consumer Key * Consumer Secret 7. Test the connection to verify access Before going live, run through the plugin checklist to verify tax calculation is set up correctly. Repeat it after any WooCommerce update, plugin update, or new state registration. ### Security considerations * API keys should be stored securely and never exposed in client-side code * Use HTTPS for all API communications * Regularly rotate API credentials * Monitor API access logs for suspicious activity ## Data entities Rootfi fetches the following data entities from WooCommerce: ### Orders Complete order information including line items, customer details, and fulfillment status. **Key fields:** * `id` - Unique order identifier * `order_number` - Human-readable order number * `status` - Order status (pending, processing, completed, etc.) * `date_created` - Order creation timestamp * `date_modified` - Last modification timestamp * `total` - Order total amount * `subtotal` - Subtotal before taxes and shipping * `total_tax` - Total tax amount * `shipping_total` - Shipping cost * `discount_total` - Total discount amount * `currency` - Order currency code * `customer_id` - Associated customer ID * `billing` - Billing address object * `shipping` - Shipping address object * `payment_method` - Payment method used * `payment_method_title` - Payment method display name * `line_items` - Array of ordered products * `shipping_lines` - Shipping method details * `tax_lines` - Tax breakdown * `fee_lines` - Additional fees * `coupon_lines` - Applied coupons * `refunds` - Refund information ### Products Product catalog including variations, pricing, and inventory. **Key fields:** * `id` - Unique product identifier * `name` - Product name * `slug` - URL-friendly product identifier * `type` - Product type (simple, variable, grouped, external) * `status` - Publication status (publish, draft, pending) * `sku` - Stock keeping unit * `price` - Current price * `regular_price` - Regular price before discounts * `sale_price` - Sale price if on sale * `date_on_sale_from` - Sale start date * `date_on_sale_to` - Sale end date * `stock_quantity` - Available stock count * `stock_status` - Stock status (instock, outofstock, onbackorder) * `manage_stock` - Whether stock is managed * `categories` - Product categories * `tags` - Product tags * `images` - Product images array * `attributes` - Product attributes * `variations` - Product variations (for variable products) * `weight` - Product weight * `dimensions` - Product dimensions (length, width, height) * `description` - Full product description * `short_description` - Short product description ### Customers Customer profiles and contact information. **Key fields:** * `id` - Unique customer identifier * `email` - Customer email address * `first_name` - Customer first name * `last_name` - Customer last name * `username` - Customer username * `date_created` - Account creation date * `date_modified` - Last modification date * `billing` - Billing address object * `first_name` * `last_name` * `company` * `address_1` * `address_2` * `city` * `state` * `postcode` * `country` * `email` * `phone` * `shipping` - Shipping address object * `first_name` * `last_name` * `company` * `address_1` * `address_2` * `city` * `state` * `postcode` * `country` * `orders_count` - Total number of orders * `total_spent` - Total amount spent * `avatar_url` - Customer avatar URL ### Inventory Stock levels and inventory management data. **Key fields:** * `product_id` - Associated product ID * `variation_id` - Variation ID (if applicable) * `sku` - Stock keeping unit * `stock_quantity` - Current stock level * `stock_status` - Stock availability status * `manage_stock` - Whether stock management is enabled * `backorders` - Backorder settings (no, notify, yes) * `low_stock_amount` - Low stock threshold ### Categories Product categorization and taxonomy. **Key fields:** * `id` - Unique category identifier * `name` - Category name * `slug` - URL-friendly identifier * `parent` - Parent category ID * `description` - Category description * `display` - Display type * `image` - Category image * `count` - Number of products in category ### Coupons Discount codes and promotional offers. **Key fields:** * `id` - Unique coupon identifier * `code` - Coupon code * `amount` - Discount amount * `discount_type` - Type of discount (percent, fixed\_cart, fixed\_product) * `description` - Coupon description * `date_expires` - Expiration date * `usage_count` - Number of times used * `usage_limit` - Maximum usage limit * `usage_limit_per_user` - Per-user usage limit * `individual_use` - Whether coupon can be used with other coupons * `product_ids` - Applicable product IDs * `excluded_product_ids` - Excluded product IDs * `minimum_amount` - Minimum order amount * `maximum_amount` - Maximum order amount ### Refunds Order refund information. **Key fields:** * `id` - Unique refund identifier * `order_id` - Associated order ID * `date_created` - Refund creation date * `amount` - Refund amount * `reason` - Refund reason * `refunded_by` - User who processed refund * `line_items` - Refunded line items ### Tax rates Tax configuration and rates. **Key fields:** * `id` - Unique tax rate identifier * `country` - Country code * `state` - State code * `postcode` - Postal code * `city` - City name * `rate` - Tax rate percentage * `name` - Tax rate name * `priority` - Tax priority * `compound` - Whether tax is compound * `shipping` - Whether tax applies to shipping * `class` - Tax class ## API endpoints Rootfi uses the following WooCommerce REST API endpoints: ### Orders * `GET /wp-json/wc/v3/orders` - List all orders * `GET /wp-json/wc/v3/orders/{id}` - Get single order * `POST /wp-json/wc/v3/orders` - Create order * `PUT /wp-json/wc/v3/orders/{id}` - Update order ### Products * `GET /wp-json/wc/v3/products` - List all products * `GET /wp-json/wc/v3/products/{id}` - Get single product * `POST /wp-json/wc/v3/products` - Create product * `PUT /wp-json/wc/v3/products/{id}` - Update product ### Customers * `GET /wp-json/wc/v3/customers` - List all customers * `GET /wp-json/wc/v3/customers/{id}` - Get single customer * `POST /wp-json/wc/v3/customers` - Create customer * `PUT /wp-json/wc/v3/customers/{id}` - Update customer ### Product variations * `GET /wp-json/wc/v3/products/{product_id}/variations` - List variations * `GET /wp-json/wc/v3/products/{product_id}/variations/{id}` - Get variation ### Categories * `GET /wp-json/wc/v3/products/categories` - List categories * `GET /wp-json/wc/v3/products/categories/{id}` - Get category ### Coupons * `GET /wp-json/wc/v3/coupons` - List coupons * `GET /wp-json/wc/v3/coupons/{id}` - Get coupon ### Refunds * `GET /wp-json/wc/v3/orders/{order_id}/refunds` - List refunds * `GET /wp-json/wc/v3/orders/{order_id}/refunds/{id}` - Get refund ### Tax rates * `GET /wp-json/wc/v3/taxes` - List tax rates * `GET /wp-json/wc/v3/taxes/{id}` - Get tax rate ## Webhooks Rootfi configures webhooks to receive real-time updates from WooCommerce. ### Supported webhook events **Orders:** * `order.created` - New order created * `order.updated` - Order updated * `order.deleted` - Order deleted **Products:** * `product.created` - New product created * `product.updated` - Product updated * `product.deleted` - Product deleted **Customers:** * `customer.created` - New customer registered * `customer.updated` - Customer profile updated * `customer.deleted` - Customer deleted **Inventory:** * `product.updated` - Stock level changed (via product update) ### Webhook configuration Webhooks are automatically configured during the integration setup: 1. Rootfi creates webhook subscriptions via the WooCommerce API 2. Webhook endpoint: `https://api.rootfi.com/webhooks/woocommerce/{integration_id}` 3. Webhook secret is generated for signature verification 4. Events are delivered in real-time as they occur ### Webhook payload Each webhook includes: * `event` - Event type * `created_at` - Event timestamp * `resource` - Resource type (order, product, customer) * `data` - Complete resource data ### Webhook security * All webhooks are signed with HMAC-SHA256 * Signatures are verified before processing * Invalid signatures are rejected * Webhook endpoints use HTTPS only ## Data synchronization ### Initial sync When you first connect a WooCommerce store: 1. Rootfi fetches all historical data 2. Data is processed in batches to avoid rate limits 3. Sync progress is tracked and resumable 4. Typical sync time: 5-30 minutes depending on store size ### Incremental sync After initial sync: 1. Webhooks provide real-time updates 2. Periodic polling ensures data consistency 3. Modified records are detected and updated 4. Deleted records are marked as inactive ### Rate limits WooCommerce API rate limits: * Default: 25 requests per 10 seconds * Configurable per store * Rootfi automatically handles rate limiting with exponential backoff ## Troubleshooting ### Common issues **Authentication failed:** * Verify API credentials are correct * Ensure REST API is enabled in WooCommerce settings * Check that HTTPS is enabled on your store * Confirm the API user has admin permissions **Missing data:** * Check that the API user has appropriate permissions * Verify the data exists in WooCommerce * Review API rate limits and sync status * Check webhook delivery logs **Webhook not receiving updates:** * Verify webhook is active in WooCommerce settings * Check webhook delivery logs in WooCommerce * Ensure firewall allows outbound connections * Verify webhook URL is accessible **Sync performance issues:** * Large product catalogs may take longer to sync * Consider increasing API rate limits * Check for API errors in logs * Monitor server resources ### Support For additional help: * Check Rootfi integration logs * Review WooCommerce system status * Contact Rootfi support with integration ID * Provide relevant error messages and timestamps ## Best practices 1. **Regular monitoring**: Check sync status and webhook delivery regularly 2. **API key rotation**: Rotate API credentials periodically for security 3. **Test environment**: Test integration changes in staging before production 4. **Data validation**: Verify critical data after initial sync 5. **Error handling**: Monitor error logs and set up alerts for failures 6. **Performance optimization**: Use webhooks for real-time updates instead of frequent polling 7. **Backup**: Maintain regular backups of your WooCommerce data ## Limitations * Historical data retention depends on WooCommerce configuration * Some custom fields may require additional mapping * Third-party plugin data may not be included by default * API rate limits may affect sync speed for large stores * Webhook delivery is not guaranteed (use polling as backup) ## Next steps * [WooCommerce Plugin Checklist](/integrations/woocommerce/plugin-checklist) * [Supported integrations](/integrations/supported-integrations) # Xero Source: https://docs.commenda.io/integrations/xero/overview Connect Xero to sync accounting data and automate indirect tax calculations ## Overview The Xero integration connects your Xero account to Commenda for automatic transaction syncing and real-time indirect tax calculation. Commenda pulls your invoices, credit notes, contacts, and items, then calculates and applies the correct indirect tax on your Xero documents. ## Supported features | Feature | Status | | ------------------- | --------- | | Transaction syncing | Supported | | Tax calculation | Supported | | Real-time webhooks | Supported | ## Data models Commenda syncs the following data from Xero: * **Invoices** — accounts receivable invoices with line items * **Invoice credit notes** — credits issued against invoices * **Bills** — accounts payable purchase bills * **Bill credit notes** — credits received against bills * **Cash refunds** — refund transactions * **Contacts** — customer and vendor profiles with addresses * **Items** — your product and service catalog ## How tax calculation works When you create or update an invoice in Xero, Commenda automatically: 1. Receives a webhook notification from Xero 2. Fetches the full invoice and associated contact details 3. Determines the shipping address from the contact's address records 4. Calculates the applicable indirect tax 5. Creates or updates Commenda-specific tax codes in your Xero account and applies them to the invoice Commenda dynamically creates tax codes in Xero for each effective tax rate, so your tax reporting stays accurate. Tax calculation is supported for accounts receivable invoices (`ACCREC`), accounts receivable credit notes (`ACCRECCREDIT`), and cash refunds. Bills and bill credit notes are synced for data tracking but are not processed for tax calculation. ## How Commenda updates Xero documents When Commenda calculates tax on a Xero invoice or credit note, it appends a single tax line item to the document and applies the calculated tax rate to your existing line items. Your original line items remain intact — Commenda does not overwrite the account codes you set on them. ### Tax line item The appended tax line uses the following values: | Field | Value | | ------------ | -------------------------------------------------------------------------------------- | | Description | `US Sales Tax` | | Quantity | `1` | | Unit amount | The total calculated tax | | Account code | `Sales Tax` | | Tax type | The Commenda-managed tax code for the applicable rate (for example, `Sales Tax 8.25%`) | Because the tax line carries a stable description, you can filter or report on Commenda-applied tax across your Xero documents by searching for `US Sales Tax`. ### Sales Tax liability account The first time Commenda needs to write a tax line to a Xero document, it creates a dedicated liability account in your chart of accounts: | Field | Value | | ----------- | ---------------------- | | Name | `Sales Tax` | | Code | `Sales Tax` | | Type | `LIABILITY` | | Description | `Commenda Tax Account` | This account is used as the destination for collected sales tax, which is the standard accounting treatment for indirect tax payable to a tax authority. Commenda reuses this account for all subsequent tax lines. If you previously had a Commenda-created `SALES` account named **Commenda Tax** (code `COMMENDA`) from an earlier version of the integration, Commenda will create the new `Sales Tax` liability account alongside it. New tax lines will use the liability account. You can leave the old account in place or archive it once historical reporting is complete. ## Address resolution Xero does not store addresses at the invoice level. Instead, Commenda resolves the tax jurisdiction by looking at the **contact's addresses**: 1. **STREET address** — treated as the shipping address 2. **POBOX address** — treated as the billing address Commenda uses the shipping (STREET) address when available. If no shipping address exists, it falls back to the billing (POBOX) address. ## Connecting Xero From your Commenda dashboard, navigate to integrations and select **Xero**. Commenda generates a secure connection link. Click the connection link to open Xero's authorization page. Sign in and grant Commenda access to your accounting data. Choose which data models to sync, set the sync frequency, and specify how far back to pull historical data. After authorization, Commenda begins the initial data sync. Check the sync status on your dashboard to confirm data is flowing. ## VAT-specific handling When syncing transactions from Xero, Commenda automatically detects and applies VAT-specific tax treatments based on Xero's tax type codes: ### Reverse charges If a line item uses the `REVERSECHARGES` tax type in Xero, Commenda sets the tax remitter type to `BUYER` on the synced transaction. This indicates that the buyer, not the seller, is responsible for remitting the tax — a common requirement for cross-border B2B transactions in VAT jurisdictions. ### VAT-exempt transactions Line items with `EXEMPTINPUT` or `EXEMPTOUTPUT` tax types in Xero are automatically marked with the `EXEMPT_PRODUCT` exemption reason. This ensures that exempt items are excluded from tax calculations and do not count toward registration thresholds. ### Customer tax identification Commenda syncs the **tax number** from Xero contacts into the `business_identification_number` field on the corresponding customer record. This is useful for storing VAT IDs and other tax registration numbers required for compliance in certain jurisdictions. When syncing invoices, Commenda also fetches the associated contact and includes their tax number as the `customer_business_identification_number` on each transaction line item. This means you can see the customer's VAT ID or tax registration number directly on each synced transaction without needing to look up the customer separately. ## Known behaviors * **Lock dates are respected** — Commenda skips invoices dated before your Xero organisation's period lock date or end-of-year lock date * Commenda skips invoices with **paid**, **voided**, or **deleted** status for tax calculation * Xero does not support shipping lines or shipping amounts on documents, so Commenda does not calculate shipping tax separately * Commenda creates tax codes dynamically in Xero as it encounters new tax rates ## Next steps * [Accounting data integrations overview](/integrations/accounting/overview) * [Supported integrations](/integrations/supported-integrations) # Zoho Books Source: https://docs.commenda.io/integrations/zoho/overview Connect Zoho Books to sync accounting data and automate indirect tax calculations ## Overview The Zoho Books integration connects your Zoho Books account to Commenda for automatic transaction syncing and real-time indirect tax calculation. Commenda pulls your invoices, credit notes, contacts, and items, then calculates and applies the correct indirect tax on your Zoho Books documents. ## Supported features | Feature | Status | | ------------------- | --------------------- | | Transaction syncing | Supported | | Tax calculation | Supported | | Real-time webhooks | Requires manual setup | ## Data models Commenda syncs the following data from Zoho Books: * **Invoices** — sales invoices with line items and addresses * **Invoice credit notes** — credits issued against invoices * **Cash refunds** — refund transactions * **Contacts** — customer and vendor profiles * **Items** — your product and service catalog ## How tax calculation works When you create or update a document in Zoho Books, Commenda automatically: 1. Receives a webhook notification from Zoho Books 2. Fetches the full document details including addresses 3. Calculates the applicable indirect tax based on the shipping address 4. Creates a **Commenda Sales Tax** tax authority in your Zoho Books account (if it doesn't already exist) 5. Applies the calculated tax using dynamically created tax codes Commenda tracks the tax calculation status using a custom field called **"Commenda Tax Status"** on your documents. Tax calculation supports invoices, sales orders, credit notes, and estimates. ## Address resolution Commenda determines the tax jurisdiction using the **shipping address** on the document. If no shipping address is present, it falls back to the **billing address**. Both addresses are read directly from the Zoho Books document payload, so no additional API calls are needed. ## Connecting Zoho Books From your Commenda dashboard, navigate to integrations and select **Zoho Books**. Commenda generates a secure connection link. Click the connection link to open the Zoho Books authorization page. Sign in and grant Commenda access to your accounting data. Zoho Books requires manual webhook configuration. In your Zoho Books account, navigate to **Settings** > **Automation** > **Webhooks** and create a webhook that points to the Commenda endpoint provided in your dashboard. Choose which data models to sync, set the sync frequency, and specify how far back to pull historical data. After setup, Commenda begins the initial data sync. Check the sync status on your dashboard to confirm data is flowing. Unlike other integrations, Zoho Books requires you to manually configure webhooks. Without this step, real-time tax calculation will not work. ## Known behaviors * **Non-taxable transactions are skipped** — if a document is marked as `is_taxable: false` in Zoho Books, Commenda does not calculate tax on it to avoid infinite calculation loops * Commenda skips invoices with **paid** or **void** status for tax calculation * Commenda skips sales orders and credit notes with **void** or **closed** status * Commenda automatically creates a "Commenda Sales Tax" tax authority and corresponding tax codes in your Zoho Books account ## Next steps * [Accounting data integrations overview](/integrations/accounting/overview) * [Supported integrations](/integrations/supported-integrations) # Key concepts Source: https://docs.commenda.io/introduction/key-concepts Understand the core concepts and terminology used throughout Commenda. Commenda operates across many countries and regions. Throughout this documentation, we use jurisdiction-agnostic language that applies regardless of where your business operates. ## Company A **company** is your top-level account in Commenda. It represents the parent organization that owns or manages one or more business entities. All your team members, settings, and billing are managed at the company level. ## Entity An **entity** (also called a corporation) is an individual legal business — such as a C-Corp, LLC, Private Limited company, or LLP. A single company in Commenda can manage dozens or even hundreds of entities across different countries and jurisdictions. Each entity has its own: * Business information (name, EIN, formation date) * Key persons (directors, officers, signatories) * Ownership structure (stakeholders, cap table) * Registrations (tax IDs, state registrations) * Documents ## Jurisdiction A **jurisdiction** is any taxing authority — a country, state, province, emirate, or other governmental region that imposes tax obligations. Commenda helps you manage compliance across multiple jurisdictions from a single platform. ## Indirect tax **Indirect tax** refers to consumption-based taxes such as VAT, GST, sales tax, and similar levies that are collected on goods and services. Commenda helps you manage the full lifecycle of indirect tax compliance — from tracking when you need to register, through filing returns and managing exemptions. ## Registration threshold A **registration threshold** is the point at which you become required to register for indirect tax collection in a given jurisdiction. Thresholds vary by jurisdiction and are typically based on revenue, transaction volume, or physical presence. Commenda tracks your activity against these thresholds automatically and alerts you when action is needed. ## Compliance item A **compliance item** is a specific obligation your entity needs to fulfill — such as filing an annual report, paying franchise tax, or submitting a tax return. Commenda generates compliance items automatically based on your entity's type, jurisdiction, and registration status. Each compliance item has a due date, status, and can be linked to a service request if you need help completing it. ## Compliance calendar The **compliance calendar** is a centralized view of all your upcoming filing deadlines and compliance tasks across every entity and jurisdiction. It helps you stay ahead of obligations and avoid missed deadlines. ## Service request A **service request** is a unit of work being done on your behalf — like incorporating a new entity, filing a tax return, or registering for indirect tax. Service requests track tasks, assignees, deadlines, and related documents. You can create service requests in three ways: * Manually from your team * Through the service marketplace * Automatically from compliance items ## Task A **task** is an individual action item within a service request. Tasks are assigned to specific people (you, your advisor, or a Commenda agent) and tracked through completion. Tasks have statuses like **Not started**, **In progress**, **Action required**, and **Completed**. ## Key person A **key person** is a director, officer, signatory, or other individual associated with one of your entities. You manage key persons centrally, so you can link the same individual to multiple entities without duplicating their information. ## Registration A **registration** is a record of your entity being registered with a government authority — such as a state tax registration, business license, or employer ID. Registrations track the registration number, status, filing frequency, and associated credentials. ## Advisor firm An **advisor firm** (also called an accountant firm or CA firm) is an external accounting or advisory firm that works with your company through Commenda. Advisor firms can view your entities, manage compliance work, and deliver services on your behalf. The Advisor Portal is a dedicated view within Commenda where advisors can manage their client portfolio, assign team members, create proposals, and monitor compliance status across all clients. ## Agent firm An **agent firm** is a service provider that handles specific tasks like incorporation filings, registered agent services, or tax registrations. Agent firms work through the Commenda agent portal to deliver services assigned to them. ## Integration An **integration** is a connection between Commenda and an external system — like your accounting software (QuickBooks, Xero, etc.) or bank account (via Plaid). Integrations automatically sync data so you don't need to enter it manually. # Navigating the platform Source: https://docs.commenda.io/introduction/navigation-guide Learn how to navigate Commenda's interface and find what you need. Commenda's interface is organized around a collapsible sidebar, a top navigation bar, and context-specific tabs within each section. ## Sidebar navigation The sidebar is your primary way to move between sections. You can collapse it to show only icons or expand it to show full labels. Click the collapse button at the bottom of the sidebar to toggle. Your sidebar contents depend on your [user role](/introduction/user-roles). ### For company users The sidebar is organized into three groups: **Main** * **Home** — Dashboard with active services, tasks, and entity overview * **Entities** — All your business entities and their details **Compliance** * **Compliance calendar** — Upcoming filing deadlines and compliance tasks * **Services** — Service marketplace for professional services * **Indirect tax** — Manage registrations, filings, exemptions, calculations, transactions, and products for each entity * **Transfer pricing** — Intercompany transaction documentation (where enabled) **Platform** * **Settings** — Company settings, team management, billing, integrations, and preferences ### For advisor users | Section | What it contains | | ----------------- | -------------------------------------- | | **Clients** | All assigned client entities | | **Team members** | Your firm's team and their assignments | | **Services** | Service catalog and marketplace | | **Proposals** | Service proposals for clients | | **Audit reports** | Audit documentation | | **Settings** | Firm settings and preferences | ## Top bar The top navigation bar provides: * **Account switcher** — Switch between companies if you have access to multiple * **Entity selector** — Switch between your entities to view entity-specific data. Each entity may have different features enabled and different compliance obligations. * **Notifications** — Alerts for tasks, service request updates, and messages * **Profile** — Your account settings and sign-out option ## Entity-level navigation When viewing a specific entity, you'll see tabs for: * **Business information** — core entity details * **Key persons** — directors, officers, signatories * **Ownership** — stakeholders and cap table * **Registrations** — government and tax registrations * **Documents** — uploaded and generated files ## Indirect tax sub-navigation Within the **Indirect Tax** section, each entity has its own set of tabs: * **Dashboard** — Overview of your indirect tax compliance status * **Registrations** — Track and manage jurisdiction registrations * **Filings** — View and manage tax return filings * **Exemptions** — Manage customer exemption certificates * **Calculations** — Run and review tax calculations * **Transactions** — View imported and manual transaction records * **Products** — Manage product tax classifications * **Customers** — View and manage customer records * **Settings** — Entity-specific indirect tax configuration If you manage multiple entities, use the entity selector in the top bar to switch context. Each entity may have different features enabled and different compliance requirements based on where it operates. # How Commenda works Source: https://docs.commenda.io/introduction/platform-overview A high-level overview of how Commenda works and what it offers. Commenda is organized around three interconnected portals, each designed for a specific user type. ## The three portals ### Company portal The main platform for businesses. As a company user, you can: * Manage entities (corporations, LLCs, etc.) across 100+ countries * Track compliance obligations with an auto-generated compliance calendar * Handle indirect tax registrations, transactions, filings, and exemptions * Document transfer pricing policies and benchmarking * Browse and purchase services from the marketplace * Manage documents, key persons, and corporate structure * Connect accounting software and bank accounts ### Advisor portal For accounting and advisory firms that serve company clients: * View and manage assigned client entities * Handle compliance work and update filing statuses * Deliver services through service requests * Manage team members and their client assignments * Access document templates * Create proposals and audit reports ### Service provider portal For agent firms that deliver specific services: * Complete assigned service requests * Manage client entities during service delivery * Handle incorporation filings across supported countries * Track SLA compliance and team workload These portals share data automatically. When you submit a service request, it appears in the service provider's inbox. When an advisor adds a client, that client's compliance data becomes visible in the Advisor Portal. ## Core workflow Add your business entities with their details, key persons, registrations, and documents. Enable features for each entity based on your needs — indirect tax management, compliance monitoring, tax and reporting, and more. Connect your integrations (Shopify, Xero, QuickBooks, Stripe, etc.) to automatically import transaction and financial data. Commenda generates your compliance calendar automatically. It tracks your activity against registration thresholds in each jurisdiction and alerts you when action is needed. Handle filings yourself, or use the service marketplace to get professional help. Track progress through service requests with built-in chat and SLA timelines. Monitor service requests, communicate with your advisors, and keep documents in one place. The compliance calendar surfaces all upcoming deadlines across your entities and jurisdictions. ## Supported jurisdictions Commenda supports entity management and compliance tracking in 100+ countries. Incorporation services are available in: * United States (all 50 states) * Canada * United Kingdom * Ireland * Singapore * UAE * India Indirect tax features support US multi-state sales tax compliance, EU VAT, and expanding international coverage. ## Integrations Commenda connects to your existing business tools to automatically import transaction and financial data: * **Shopify** — eCommerce transactions and order data * **Stripe** — Payment processing and subscription data * **Xero** — Accounting and financial data * **QuickBooks** — Accounting and bookkeeping data * **NetSuite** — ERP and financial management data * **Zoho** — Business and accounting data * **WooCommerce** — eCommerce transactions and order data Integrations keep your compliance data up to date without manual data entry. You can connect multiple integrations per entity. ## Security and data Commenda uses a multi-tenant architecture with strict data isolation between organizations. Commenda logically separates each organization's data and restricts access to authorized users. Document management includes secure information request workflows for safely exchanging sensitive compliance documents with your service providers. # Quickstart Source: https://docs.commenda.io/introduction/quickstart Get your company set up on Commenda in just a few minutes. This guide walks you through the essential steps to get up and running on Commenda. ## Prerequisites Before you begin, you need: * A Commenda account (sign up at [app.commenda.com](https://app.commenda.com)) * At least one legal entity you want to manage compliance for ## For company users ### Step 1: Create your account Go to [app.commenda.com](https://app.commenda.com) and sign up with your email address or Google account. You'll receive a verification email — click the link to confirm your account. ### Step 2: Enter your company details After signing in, you'll be guided through the onboarding flow: 1. **Company information** — enter your company name and basic details. 2. **Your profile** — add your name and role within the company. ### Step 3: Add your entities Once your company is set up, add the business entities (corporations, LLCs, etc.) that your company manages. Click **Entities** in the sidebar navigation. Click the **Add entity** button and fill in the details: entity name, country of incorporation, entity type, and jurisdiction. For each entity, add key details like EIN/tax ID, formation date, addresses, and registered agent information. If you have many entities to add, your Commenda account manager can help you bulk-import them. ### Step 4: Set up your corporate structure If your entities have parent-subsidiary relationships, joint ventures, or other connections, you can define your corporate structure: 1. Go to **Entities** and select an entity. 2. Navigate to the **Ownership** tab. 3. Add relationships to other entities in your company. ### Step 5: Connect your integrations Go to **Settings > Integrations** and link your data sources — Shopify, Xero, QuickBooks, Stripe, or others. This imports your transaction data automatically. ### Step 6: Review your compliance calendar Commenda automatically generates compliance obligations based on your entities and their jurisdictions. Go to **Compliance Calendar** in the sidebar to see upcoming deadlines and track your filing status. ## For advisor users Create your Advisor account and configure your firm profile, including your firm name, contact details, and service offerings. From the **Clients** section in your Advisor Portal, add your client businesses. You can invite clients directly or create their accounts on their behalf. Navigate to **Team Members** to add your team and assign them to specific client accounts. This controls who can view and manage each client's compliance data. Use your Advisor Portal dashboard to monitor compliance status, filing deadlines, and alerts across your entire client portfolio. ## What's next? Connect your accounting software and start tracking indirect tax obligations. Browse professional services available through Commenda's service marketplace. Now that you are set up, explore the platform in more depth: * **[How Commenda works](/introduction/platform-overview)** — Understand the full platform architecture and core workflows * **[Navigating the platform](/introduction/navigation-guide)** — Learn how to find your way around the interface * **[Key concepts](/introduction/key-concepts)** — Review the terminology used throughout the platform and documentation # User roles Source: https://docs.commenda.io/introduction/user-roles Understand the different user types and roles available in Commenda. Commenda is a multi-tenant platform with three distinct user experiences. Your role determines which features, dashboards, and navigation items are available to you. ## Company users As a company user, you manage your own tax compliance and corporate operations. ### Company roles | Role | Description | | ----------------- | ------------------------------------------------------------------------------------------------------------------- | | **Company Admin** | Full access to all company data, entities, and settings. Can manage team members and billing. | | **Company User** | Full access to company data and entities. Cannot manage team members. | | **Accountant** | Access to financial data across entities. Designed for external accountants and advisors. | | **Controller** | Access limited to specific entities assigned to them. Useful for team members who manage a subset of your entities. | | **Employee** | Limited access to their own payroll and equity information. | | **Custom** | Permissions defined on a per-user basis. | ### What company users can access * **Home dashboard** — Overview of your entities, active services, and tasks * **Entities** — Manage your legal entities and corporate structure * **Indirect tax** — Registrations, filings, exemptions, calculations, transactions, and products * **Tax & reporting** — Direct tax compliance, fiscal year management, and filing requirements * **Compliance calendar** — All upcoming deadlines and compliance tasks * **Documents** — Document storage, organization, and secure information requests * **Service requests** — Request and track professional compliance services * **Integrations** — Connect external data sources like Shopify, Xero, and QuickBooks * **Settings** — Organization profile, team management, billing, and subscriptions ## Advisor users As an advisor user, you belong to an accounting or advisory firm that serves companies through Commenda. You access the Advisor Portal, which provides: * **Clients** — View and manage all client businesses in your portfolio * **Team members** — Add team members and assign them to specific clients * **Services** — Browse and offer marketplace services to clients * **Proposals** — Create and manage service proposals for clients * **Alerts** — Compliance and filing alerts across your entire client portfolio * **Payment management** — Track payments and billing for client services * **Settings** — Firm profile, team configuration, and preferences ## Service provider users As a service provider user, you belong to an agent firm that delivers specific services (incorporation, tax registration, registered agent, etc.) through the Commenda agent portal. You can: * **Service request inbox** — View and manage incoming compliance requests * **Client accounts** — Access client data needed to complete service work * **Document templates** — Standardized templates for compliance deliverables * **SLA management** — Track service level agreements and deadlines * **Team management** — Assign requests to team members and manage workload * **Tools** — Use e-signatures, document templates, and other delivery tools * **Settings** — Firm configuration and team preferences ## Switching between views If you have access to multiple roles (for example, you're both a company user and part of an advisor firm), you can switch between views using the account switcher in the sidebar. ## Permissions and access Your role determines which sections of the platform you can see and what actions you can take. Within each role, additional permission levels (such as admin access) control whether you can manage team members, modify organization settings, or perform other administrative tasks. Your role determines which sections of the platform — and which parts of this documentation — are most relevant to you. Look for role-specific guidance throughout the docs. # Welcome to Commenda Source: https://docs.commenda.io/introduction/welcome Commenda is the platform for managing your business entities, compliance, taxes, and corporate operations globally. Commenda helps you manage the full lifecycle of business operations — from incorporating new entities to staying on top of tax filings and compliance deadlines across every jurisdiction. ## What Commenda does Create and manage all your business entities, directors, stakeholders, and corporate structure in one place. Never miss a filing deadline. Commenda automatically generates your compliance calendar based on your entities and jurisdictions. Track registrations, transactions, exemptions, and filings across all your tax jurisdictions. Browse and purchase professional services like incorporation, tax filing, and bookkeeping from vetted providers. Store, organize, and share documents. Generate documents from templates and collect e-signatures. Connect your accounting software and bank accounts to sync financial data automatically. Manage direct tax compliance, fiscal year tracking, and filing requirements for each of your entities. Manage multiple client businesses, assign team members, create proposals, and monitor compliance across your entire client portfolio. ## Who uses Commenda Commenda serves three types of users: * **Companies** — manage your entities, compliance, and taxes through the main platform. * **Advisors and accountants** — serve your clients, manage service delivery, and collaborate on compliance work. * **Service providers** — deliver services like incorporation, tax filing, and registered agent work through the agent portal. ## How to use these docs If you're new to Commenda, start with the Introduction section: 1. **[Key concepts](/introduction/key-concepts)** — Learn the core terminology used throughout the platform and this documentation. 2. **[User roles](/introduction/user-roles)** — Understand the three user types and what each can access. 3. **[How Commenda works](/introduction/platform-overview)** — Get a high-level view of the platform architecture and core workflows. 4. **[Quickstart](/introduction/quickstart)** — Follow a step-by-step guide to get up and running. 5. **[Navigating the platform](/introduction/navigation-guide)** — Learn how to find your way around the Commenda interface. Ready to dive in? Head to the [quickstart guide](/introduction/quickstart) to get set up in minutes. # Compliance calendar Source: https://docs.commenda.io/product/compliance/compliance-calendar View all your compliance deadlines in one place. The **Compliance calendar** gives you a unified view of every filing obligation across all your entities and jurisdictions. ## Accessing the calendar Click **Compliance Calendar** in the sidebar to open it. ## What you'll see The calendar pulls obligations from two sources into a single view: * **Compliance items** — annual reports, income tax filings, franchise tax filings, and any custom obligations attached to your entities. * **Sales tax filings** — indirect tax returns generated by Commenda's sales-tax engine. Each event is keyed off its due date, so a single date can include filings from multiple sources. For each event, you can see: * **Title** — the filing name (for example, "Form 1120" or a state sales-tax return) * **Entity** — which corporation the obligation belongs to * **Category** — the obligation category (direct tax, indirect tax, annual report, custom, and so on) * **Jurisdiction** — the state or sub-jurisdiction where the filing is due * **Frequency** — how often the obligation recurs (monthly, quarterly, annual) * **Due date** — when the filing must be submitted * **Status** — current progress (upcoming, not filed, filed, overdue, and so on) * **Assignee** — the team member or partner firm responsible for the filing. Sales-tax filings handled by Commenda show "Commenda" as the assignee. If you've just created a company and haven't generated any compliance items or sales-tax filings yet, the calendar shows an empty state prompting you to set up your obligations. ## Filtering the calendar You can narrow the calendar to focus on what's relevant. Filters combine, so you can stack them to drill down quickly: * **Date range** — pick the window you want to see. The calendar supports ranges of up to **92 days** at a time, so a typical month or quarter view loads in a single request. * **Entity** — restrict the calendar to one or more corporations under the company. * **Category** — show only specific obligation categories (for example, only **Indirect Tax** to focus on sales-tax filings, or only **Direct Tax** for income-tax obligations). When you change a filter, the calendar updates both the per-day counts and the event details below. ## Calendar views Two views power the calendar UI: * **Summary view** — shows the count of events on each day in your selected range. This is what drives the heat-map style markers you see on the calendar grid, so the page loads fast even when a large window is selected. * **Day detail view** — when you click into a specific day (or load a narrow range), the full list of events on each date is returned, grouped by due date. Both views respect the same date range, entity, and category filters. ## Taking action From the compliance calendar, you can: * **Update status** — mark a filing as under filing, filed, or completed * **Create a service request** — get professional help with a filing by creating a service request * **View details** — click any item to see its full details, history, and attached documents * **Request an extension** — if available, file for an extension on the deadline Check your compliance calendar weekly to stay ahead of upcoming deadlines. Items approaching their due date will be highlighted, and the per-day counts make it easy to spot heavy filing weeks at a glance. # Compliance Source: https://docs.commenda.io/product/compliance/overview Stay on top of every filing deadline with Commenda's automated compliance tracking. Commenda's compliance features help you track and manage every regulatory obligation across all your entities and jurisdictions. Instead of manually tracking deadlines in spreadsheets, Commenda automatically generates your compliance calendar and helps you stay on top of every filing. ## How it works 1. **Automatic generation** — when you add an entity and its jurisdictions, Commenda generates the applicable compliance obligations (annual reports, tax returns, franchise tax, etc.). 2. **Calendar view** — All obligations appear in your compliance calendar with due dates, statuses, and responsible parties. 3. **Status tracking** — Track each filing through its lifecycle: not filed, under filing, filed, or completed. 4. **Service requests** — Need help filing? Create a service request directly from a compliance item to get professional assistance. ## Compliance statuses | Status | Meaning | | ---------------- | -------------------------------------------------------- | | **Not filed** | No one has started the filing yet | | **Under filing** | The filing is in progress | | **Filed** | You or your advisor submitted the filing | | **Completed** | The authority confirmed the filing | | **Rejected** | The authority rejected the filing and it needs attention | | **Archived** | The filing is no longer relevant | ## Getting started View and manage all your upcoming compliance deadlines. Learn how to update filing statuses and manage compliance items. # Recurring tasks Source: https://docs.commenda.io/product/compliance/recurring-tasks Manage recurring compliance and operational tasks that need regular attention. In addition to one-time filings, many compliance obligations require recurring attention — monthly indirect tax filings, quarterly reviews, or regular hygiene checks. Commenda tracks these as **recurring tasks**. ## Types of recurring tasks | Task type | Description | | ------------------------ | ------------------------------------------------------------------ | | **Monthly indirect tax** | Monthly indirect tax filing obligations | | **Hygiene check** | Regular review of entity information for accuracy | | **Request information** | Periodic requests to collect updated information from stakeholders | ## Viewing your tasks Your recurring tasks appear on your **Home** dashboard under the **Tasks** section. You can also find them within the compliance calendar. ## Managing tasks Each task has a status: * **Not started** — the task hasn't been addressed yet * **In progress** — someone is working on it * **Completed** — the task is done for this period * **Cancelled** — the task has been cancelled (no longer needed) Click a task to view its details, update its status, or add notes. Recurring tasks automatically regenerate for the next period once completed. You don't need to create them manually each month or quarter. # Tracking filings Source: https://docs.commenda.io/product/compliance/tracking-filings Learn how to manage the lifecycle of compliance filings in Commenda. Each compliance item in Commenda follows a lifecycle from creation to completion. This page explains how to track and manage that process. ## Filing lifecycle A typical compliance filing moves through these stages: The obligation has been identified but work hasn't started. Commenda assigns this status to newly generated compliance items by default. Someone is actively working on the filing. This could be your team, your accountant, or a Commenda service provider. You or your advisor submitted the filing to the relevant authority. The relevant authority accepted and confirmed the filing. ## Updating a filing's status 1. Navigate to **Compliance Calendar** or go to the entity's compliance tab. 2. Click on the compliance item you want to update. 3. Change the status using the status dropdown. 4. Add any notes or attach relevant documents. ## Working with your advisor If you have an advisor or accounting firm connected to your Commenda account, they can update filing statuses on your behalf. You'll see their updates reflected in your compliance calendar with a full audit trail of who made each change. ## Extensions Some filings allow you to request an extension. If an extension is available, you'll see an **Extension** option on the compliance item. Extensions create a new deadline but the original obligation remains tracked. ## Audit trail Commenda records every status change with: * Who made the change * When they made it * The previous and new status * Any notes or documents attached This provides a complete compliance history for your records. # The drive Source: https://docs.commenda.io/product/documents/drive Browse, organize, and manage documents across your entities and company. The **Drive** is the central file browser in Commenda. It shows every document stored against an entity or across your whole company, organized into a consistent folder tree that mirrors how tax, compliance, and governance work actually happens. ## Views The drive has two top-level views: * **Entity view** — the full folder tree for a single entity, with tag-based filters and dynamic folders (per person, per service request). * **Company view** — a roll-up of every entity in the company so you can see all documents from a single pane. Switch between them from the selector at the top of the drive. ## The folder tree Every entity is provisioned with the same base taxonomy the first time it's created, so documents always land in a predictable place: | Folder | What goes here | | -------------------------------------------------------- | --------------------------------------------------------- | | General | Miscellaneous files that don't fit elsewhere | | Corporate Governance → Formation Documents | Certificates of incorporation, articles, bylaws | | Corporate Governance → Key Persons | A dynamic subfolder per director, officer, or signatory | | Corporate Governance → Registrations & Licenses | Tax registrations, business licenses, government IDs | | Corporate Governance → Board & Shareholder Records | Minutes, resolutions, share certificates | | Corporate Governance → Notices and Correspondence | Government notices, letters, correspondence | | Filings & Tax Compliance → Direct Tax | Income tax filings, supporting schedules | | Filings & Tax Compliance → Indirect Tax | Sales tax, VAT, GST filings | | Filings & Tax Compliance → Transfer Pricing | Transfer pricing documentation, master files, local files | | Filings & Tax Compliance → Entity Compliance | Annual returns, registered agent filings | | Filings & Tax Compliance → Payroll & Employment | Payroll returns, employment filings | | Filings & Tax Compliance → Customs & Trade | Customs declarations, import/export documents | | Bookkeeping & Financial Reporting → Financial Statements | Balance sheets, P\&Ls, trial balances | | Service Delivery → Service Request | A dynamic subfolder per service request | Some folders (Key Persons, Service Request) generate child folders dynamically based on your data — each new director or service request gets its own folder automatically. ## Custom folders You can create your own folders anywhere in the tree if the default structure doesn't fit. Right-click a folder and choose **New folder**, or use the **+ Folder** button in the toolbar. Custom folders can be nested, renamed, moved, and deleted just like standard ones. ## File placements Files in Commenda can appear in more than one place at once — for example, a single tax filing can sit in both the **Direct Tax** folder and a **Service Request** folder. These are called *placements*. Renaming or moving a placement only affects that one copy; the underlying file is still one file with one version history. ## Organizing files From the drive you can: * **Rename** a file or folder. * **Move** files to a different folder using drag-and-drop or the **Move to** action. * **Download** individual files, multiple files, or entire folders as a zip archive. * **Trash** files and folders. See [Trash and restore](#trash-and-restore). * **Tag** files with fiscal year, period, jurisdiction, tax type, and document type. See [Tagging and filtering documents](/product/documents/tagging). Most actions support bulk selection — hold Shift or Cmd/Ctrl to select multiple files and act on them at once. ## Search The search bar at the top of the drive searches file names across every entity in the company. Results include the file, the folder it lives in, and its tags so you can jump directly to it. ## Trash and restore Deleting a file or folder moves it to **Trash** rather than destroying it. From the Trash view you can: * **Restore** a file or folder to its original location. * **Permanently delete** items you no longer need. * Preview what will be deleted before acting on a folder — Commenda shows how many files and subfolders are inside. Deleting a folder trashes everything it contains. Restoring the folder brings its contents back with it. ## Bulk download Select one or more files or folders and choose **Download** to get a zip archive. For large selections, Commenda generates the archive in the background and emails you a link when it's ready. # Document management Source: https://docs.commenda.io/product/documents/overview Store, organize, and manage all your business documents in Commenda. Commenda provides a centralized document repository — the **Drive** — for all your business files: formation documents, tax filings, contracts, certificates, and more. Every entity you create gets a pre-built folder structure so documents land in the right place automatically. ## What you can do Navigate your entity and company-level folder tree to find any document. Tag files with fiscal year, period, jurisdiction, and document type to filter and search. Send structured forms to collect data and documents from stakeholders. Produce standardized documents with automatic data filling. ## Where documents live Every entity in Commenda has a pre-provisioned folder structure organized around how you actually work: * **General** — miscellaneous files that don't fit elsewhere * **Corporate Governance** — formation documents, key persons, registrations and licenses, board and shareholder records, notices * **Filings & Tax Compliance** — direct tax, indirect tax, transfer pricing, entity compliance, payroll and employment, customs and trade * **Bookkeeping & Financial Reporting** — financial statements and supporting ledgers * **Service Delivery** — documents exchanged during a service request You can also create your own custom folders anywhere in the tree. ## Uploading files You can upload files from several places throughout the platform: * **Drive view** — navigate to any folder and upload directly * **Entity documents tab** — go to an entity and click the **Documents** tab * **Service requests** — upload files related to a specific engagement * **Compliance items** — attach filed documents for your records Commenda supports all common business document formats: PDF, Microsoft Office files, images, and CSV/data files. ## Tagging and filtering Files in the drive can be tagged with explicit metadata such as **fiscal year**, **period** (quarter, month), **jurisdiction**, **tax type**, and **document type**. Tags power the drive's filter bar so you can narrow large folders to just the files you need — for example, every Q2 FY2025 indirect-tax filing for a US entity. See [Tagging and filtering documents](/product/documents/tagging) for how tags work and how to apply them. ## Searching Use the search bar at the top of the drive to find files by name across an entire company. Results show the file, the folder it lives in, and its tags so you can jump to it in one click. ## Trash and restore Deleted files and folders move to **Trash** first. You can restore items from trash until they're permanently deleted. This applies to both individual files and entire folders (including all their contents). ## Access control You can set access controls on documents to manage who can view sensitive files: * **Private** — only visible to specified team members * **Shared** — visible to your team and your advisor * **Public** — accessible to anyone with the link ## Document templates Commenda supports document templates that let you generate standardized documents with automatic data filling. Templates pull information from your entities, directors, and other records to produce completed documents. Commenda versions templates, so changes don't affect previously generated documents. ## E-signatures Commenda integrates with DocuSign to collect electronic signatures on documents. See the [eSign tool](/product/tools/esign) for details on sending documents for signature. # Secure information requests Source: https://docs.commenda.io/product/documents/secure-information-requests Collect sensitive information and documents from stakeholders through structured, secure forms. **Secure information requests** are structured forms that your team, accountant, or service provider can send to collect specific data or documents securely. ## How they work When someone needs information from you (or you need it from a stakeholder), a secure information request is created with specific fields and file upload requirements. The recipient fills out the form and submits their response through Commenda. ## Receiving a request When you receive a secure information request: 1. You'll get a notification (email and in-app). 2. Click the link to open the request form. 3. Fill in the requested information fields. 4. Upload any required documents. 5. Submit the response. ## What requests can collect Secure information requests support different field types: * **Text fields** — for entering information like names, numbers, or descriptions * **File uploads** — for submitting documents, certificates, or images * **Confirmations** — for acknowledging or agreeing to statements ## Who sends requests Requests can come from: * **Your advisor** — collecting information needed for filings or compliance work * **Commenda's team** — gathering details for a service request * **Your own team** — collecting information from key persons or stakeholders All information submitted through secure information requests is encrypted and only accessible to authorized parties. # Tagging and filtering documents Source: https://docs.commenda.io/product/documents/tagging Use tags to classify documents by fiscal year, period, jurisdiction, and type — then filter the drive to find exactly what you need. Tags are structured labels you attach to files so Commenda can classify and filter them. Unlike folder names, tags are machine-readable: Commenda uses them to drive filters, power searches, and connect documents to the filings and service requests they relate to. ## When to use tags Use tags whenever a document has meaningful metadata beyond its name — for example, a quarterly sales-tax filing for a US entity for Q2 of FY2025. Tagging the file lets you: * Filter the drive to just the files that match certain criteria. * Find every document for a specific jurisdiction across all your entities. * Show the right documents automatically in compliance and service-request views. ## Tag types Commenda supports several tag categories: | Tag | Example values | What it represents | | ----------------- | -------------------------------------------- | ---------------------------------------------- | | **Fiscal year** | FY2024, FY2025 | The fiscal year the document belongs to | | **Period** | Q1, Q2, Month 1, Month 6 | The quarter or month within a fiscal year | | **Jurisdiction** | US, IN, SG, Delaware, California | The country or region the document is filed in | | **Tax type** | Income Tax, GST, VAT, Sales Tax | The tax the document relates to | | **Source type** | Upload, Filing, Service Request, Integration | Where the document came from | | **Document type** | Invoice, Return, Notice, Certificate | The kind of document | Fiscal year and period are *explicit* tags — every file can have at most one of each. Jurisdiction, tax type, and document type can have multiple values when it makes sense (for example, a consolidated filing covering multiple states). ## Applying tags From the drive, select a file and open the details panel. You'll see a **Tags** section where you can: * Add tags by typing or picking from the dropdown of available values. * Remove a tag with the **×** next to it. * Assign a **document type** from the dropdown — this is a special tag that enables type-specific behaviour (for example, invoice parsing). For files uploaded through a service request or a filing workflow, Commenda applies tags automatically based on the context of the upload. You can always adjust them afterwards. ## Filtering the drive The entity drive view has a filter bar at the top with dropdowns for each tag type. Pick any combination — for example, *FY2025 + Q2 + US + Indirect Tax* — and the drive narrows to only placements that match. The folder tree collapses to hide folders that contain no matching files, so you see exactly the scope you asked for. Filters are additive: every file in the filtered view matches **all** of the selected criteria. ## Clearing tags To clear a tag from a file, open the details panel and click the **×** next to the tag. To clear all tags, use **Clear tags** from the file's action menu. Clearing a tag doesn't delete the file — it only removes the metadata. # Bank accounts Source: https://docs.commenda.io/product/entities/bank-accounts Link and manage bank accounts for your business entities. Each entity in Commenda can have one or more bank accounts linked for financial data visibility and transaction tracking. ## Connecting a bank account via Plaid Navigate to **Entities** and select the entity whose bank account you want to connect. In the entity details page, click the **Bank Accounts** tab. Click the **Add Bank Account** button. You'll be guided through Plaid's secure connection flow. Search for your bank and sign in with your banking credentials. Plaid handles the authentication securely. Select which accounts to connect (checking, savings, etc.). Once connected, Commenda can access: * **Account balances** — current balance information * **Transactions** — transaction history for reconciliation and tax purposes * **Account details** — account type and institution information Plaid supports thousands of financial institutions. If your bank isn't available, manual entry is always an option. ## Manual entry If your bank isn't available through Plaid, you can manually enter account details. The form adapts based on the country you select, so you only see fields relevant to your bank's location. **Fields required for all countries:** * **Bank name** — the full name of your financial institution * **Account holder name** — the legal name on the account (should match your entity name) * **Country** — the country where your bank account is held * **Currency** — the account currency (USD, EUR, GBP, INR, etc.) **Country-specific fields** appear after you select a country. For example: * **US accounts** — routing number and account number * **Indian accounts** — IFSC code and account number * **UK accounts** — sort code and account number * **Canadian accounts** — transit number, institution number, and account number * **EU accounts** — IBAN (and optionally SWIFT/BIC) Double-check your account and routing numbers before saving. Incorrect numbers can cause payment failures. ## Managing bank accounts From an entity's Bank Accounts tab, you can: * **Set a primary account** — designate one account as the default for transactions and payments. Only one account can be primary at a time. * **Edit account details** — update bank name, account holder name, account type, currency, credentials, or primary status * **View account details** — see masked account number (last 4 digits), routing information, account type, country, currency, and date added * **Remove an account** — disconnect or delete a bank account from the entity You cannot edit the account number or routing number after creation. If these need to change, add a new account with the correct information and delete the old one. ## Security Bank connections through Plaid use bank-level encryption. Commenda never stores your banking login credentials. For manually entered accounts, account numbers are masked in the dashboard and only show the last 4 digits. You can disconnect your account at any time. ## Troubleshooting ### I can't save my bank account **Common causes:** * Missing required fields (bank name, account holder name, country, and the country-specific fields shown in the form) * Invalid format for country-specific fields (e.g., routing number must be 9 digits for US banks, IFSC code must be 11 characters for Indian banks) * Account number contains invalid characters **Solution:** Check that all required fields are filled and formatted correctly. The form validates fields based on the country you selected. ### I need to change my account number You cannot edit account or routing numbers after creation. Add a new bank account with the correct information, set it as primary if needed, then delete the old account. ### The primary account won't change Check that you have permission to edit bank accounts, the new account is fully saved, and you're clicking **Save** after making changes. ## Best practices * **Keep information current** — update bank details immediately when accounts change * **Verify before saving** — always double-check account and routing numbers * **Set a primary account** — designate one account as primary for streamlined operations * **Match legal names** — use the exact legal name registered with your bank to avoid payment issues # Business information Source: https://docs.commenda.io/product/entities/business-information Maintain key details for each of your business entities. Each entity in Commenda has a **Business information** tab where you can view and edit its core details. ## Accessing business information 1. Go to **Entities** in the sidebar. 2. Click on an entity. 3. Select the **Business information** tab. ## What you can track ### Basic details * **Legal name** — the registered name of the entity * **Entity type** — legal structure (C-Corp, LLC, etc.) * **Country and jurisdiction** — where the entity is incorporated * **Formation date** — when the entity was incorporated * **EIN / Tax ID** — the employer identification number or equivalent * **Fiscal year end** — used for compliance calendar generation ### Addresses Each entity can have multiple addresses: * **Incorporation address** — the address on file with the state of incorporation * **Operating address** — where the entity conducts business * **Mailing address** — where correspondence is sent ### Registered agent If your entity uses a registered agent for service of process, you can record their details here. ## Editing information Click the **Edit** button on any section to update the details. Changes are saved immediately and reflected across the platform, including in your compliance calendar and service requests. Changing an entity's jurisdiction or entity type may affect its compliance obligations. Review your compliance calendar after making these changes. # Corporate structure Source: https://docs.commenda.io/product/entities/corporate-structure Define relationships between your entities to map your corporate structure. If your company has multiple entities with ownership or operational relationships, you can map your corporate structure in Commenda. ## Relationship types Commenda supports the following relationship types between entities: | Relationship | Description | | -------------------------- | -------------------------------------------------------------- | | **Parent / Subsidiary** | One entity owns or controls another | | **Joint venture** | Two or more entities share ownership of a venture | | **Sister company** | Entities that share a common parent | | **Affiliate** | Entities with a business relationship but not direct ownership | | **Supplier / Customer** | Entities with a commercial trading relationship | | **Mergers & Acquisitions** | Entities involved in M\&A activity | ## Setting up relationships Navigate to **Entities** and select one of the entities in the relationship. Click the **Ownership** tab. Click **Add relationship** and select the other entity and the relationship type. ## Org chart view Open **Corporate structure** from the company-level navigation to see every entity in your group as a diagram, with the ownership percentages and key persons of each entity laid out as a graph. The view is generated automatically from the shareholdings recorded on the [Ownership](/product/entities/ownership) tab — you do not maintain it separately. Each node in the diagram includes: * The entity's legal name and incorporation country * The entity type and tax classification * A summary of the entity's key persons and bank accounts Edges show the ownership percentage between a parent and a subsidiary, and highlight any link where the parent has significant control. Control-only links — where a corporate shareholder holds 0% but exercises significant control — are rendered as dashed edges to distinguish them from equity ownership. If your workspace contains entities that are not yet linked into the structure, the org chart shows a banner above the diagram listing the unlinked entities so you can attach them. ## Why corporate structure matters Defining your corporate structure is important for: * **Transfer pricing** — intercompany transactions require documentation when entities are related * **Compliance** — some jurisdictions have specific filing requirements for parent-subsidiary relationships * **Beneficial ownership reporting** — many jurisdictions require disclosure of indirect UBOs that arise through the structure * **Reporting** — Commenda can generate reports that reflect your complete corporate hierarchy # Creating entities Source: https://docs.commenda.io/product/entities/creating-entities Learn how to add new business entities to your Commenda account. You can add entities to Commenda whether they already exist or you're incorporating a brand new one. ## Adding an existing entity If your entity is already incorporated and you want to track it in Commenda: Click **Entities** in the sidebar. Click the **Add entity** button in the top right. Fill in the required fields: * **Entity name** — the legal name of the business * **Country** — where the entity is incorporated * **Entity type** — the legal structure (e.g., LLC, C-Corp, Pvt Ltd) * **Jurisdiction** — the state or region of incorporation If the entity is **not** part of your controlled portfolio — for example a joint venture, a partner-owned holding company, or a shareholder entity that sits above your own group — toggle **This is a non-controlled entity** before saving. Non-controlled entities are kept out of: * Entity dropdowns and pickers across the app * Compliance task generation and notifications * Sales tax rollups and exposure calculations * Billing and agent-firm client lists They remain visible on the [Corporate structure](/product/entities/corporate-structure) org chart and on the [Ownership](/product/entities/ownership) tab of any controlled entity they own, so the ownership graph stays accurate without polluting your day-to-day surfaces. Click **Save** to create the entity. You can add more details like EIN, addresses, and directors later. ## Incorporating a new entity If you need to form a brand new entity, you can start the incorporation process directly from Commenda: 1. Go to **Entities** and click **Add entity**. 2. Select **Incorporate a new entity**. 3. Choose the country and entity type. 4. Follow the guided incorporation wizard, which collects all the information needed for your jurisdiction. Commenda supports incorporation in the United States, Canada, United Kingdom, Ireland, Singapore, UAE, and India. The incorporation wizard adapts to the requirements of each country. Incorporation is handled by Commenda's vetted agent partners. Once you submit the incorporation request, you'll receive a service request to track the progress. ## After creating an entity Once your entity is created, you should: 1. **Add business information** — EIN/tax ID, formation date, fiscal year end 2. **Add key persons** — directors, officers, and authorized signatories 3. **Add registrations** — state registrations, tax IDs, and business licenses 4. **Upload documents** — formation documents, bylaws, operating agreements These details help Commenda generate accurate compliance obligations and keep your records complete. # Key persons Source: https://docs.commenda.io/product/entities/key-persons Manage directors, officers, and signatories for your entities. **Key persons** are the individuals associated with your entities — directors, officers, authorized signatories, and other roles required by law or your governing documents. ## Managing key persons 1. Go to **Entities** and select an entity. 2. Click the **Key persons** tab. 3. Here you can view all individuals linked to the entity and their roles. ## Adding a key person Click the **Add** button on the Key persons tab. Provide the person's name, email, and role (director, officer, signatory, etc.). Depending on the entity's jurisdiction, you may need to provide: * Date of birth * Nationality * Residential address * Government ID numbers (e.g., SSN, PAN) * Passport or identification documents Click **Save** to link this person to the entity. ## Shared key persons If the same individual serves as a director or officer across multiple entities, Commenda manages them centrally. When you update a person's contact information, it's reflected across all entities they're linked to. ## Removing a key person To remove a key person from an entity, go to their profile within the entity and click **Remove**. This only removes the association — it does not delete the person's record from Commenda. # Entity management Source: https://docs.commenda.io/product/entities/overview Manage all your business entities, their details, key persons, and corporate structure from one central place. The **Entities** section is where you manage all the legal businesses your company owns or operates. Whether you have a single LLC or a complex multi-national corporate structure with dozens of subsidiaries, Commenda keeps everything organized. ## What you can do Maintain key details like EIN, formation date, addresses, and registered agent. Track directors, officers, and signatories across all your entities. Set up stakeholders, share classes, and cap table information. Manage tax registrations, business licenses, and government IDs. Link and manage bank accounts for each entity. Define parent-subsidiary relationships, joint ventures, and affiliates. ## Navigating to your entities Click **Entities** in the sidebar to see a list of all entities in your company. From there, you can: * Search and filter entities by name, country, or type * Click any entity to view its full details * Add new entities using the **Add entity** button ## Supported entity types Commenda supports a wide range of entity types across 100+ countries, including: | Country | Supported types | | -------------- | ------------------------------------------------------------------------------------------------------------------------ | | United States | C-Corp, LLC, S-Corp, Nonprofit | | India | Private Limited, LLP, OPC, Section 8, Public Limited | | United Kingdom | Ltd, LLP | | Canada | Corporation | | Singapore | Pte Ltd | | UAE | PJSC, Free Zone Entity, Civil Company, Foreign Branch | | Philippines | Domestic Corporation, Stock Corporation, Close Corporation, One Person Corporation, Partnership, Branch Office, and more | | Ireland | Ltd | | Germany | GmbH | | Netherlands | BV | | And many more | 50+ entity types across 100+ countries | # Ownership and beneficial owners Source: https://docs.commenda.io/product/entities/ownership Track shareholders, ultimate beneficial owners (UBOs), and stock classes for each entity. The **Ownership** tab lets you track who owns each entity and who controls it. Commenda records both **shareholders** (individuals or corporate entities holding equity) and **ultimate beneficial owners (UBOs)** — the natural persons who ultimately own or control the entity, as required by KYC and beneficial ownership reporting rules in most jurisdictions. The redesigned Ownership experience is rolling out progressively. If you do not yet see the features described below, your workspace is still on the legacy cap table view — your account team will let you know when the new experience is enabled. ## Viewing ownership 1. Go to **Entities** and select an entity. 2. Click the **Ownership** tab. The Ownership tab is organized into three sections: * **Shareholders** — every individual and corporate entity that holds equity in the entity, with their ownership percentage, relationship type, and stock class. * **Ultimate beneficial owners** — the natural persons who own or control the entity, either directly or indirectly through corporate shareholders. UBOs are computed automatically based on the shareholding tree and your jurisdiction's UBO threshold. * **Recent documents** — recently uploaded entity documents (incorporation certificates, share certificates, register extracts, etc.). The header shows the total ownership recorded against the entity. Commenda enforces a **100% ownership budget** — you cannot add or edit a shareholder if the resulting total would exceed 100%. ## Adding a shareholder Click **Add shareholder** and choose whether the new shareholder is an individual or another entity in your workspace. ### Individual shareholder For an individual, provide: * **First and last name** * **Date of birth** * **Nationality** * **Ownership percentage** (0–100) * **Relationship type** — Founder, Investor, Employee, Board member, Advisor, or Other * **Stock class** (optional) — see [Stock classes](#stock-classes) * **Significant control** (optional) — mark the person as having significant control even if they are also a shareholder; you can then pick a [control type](#beneficial-owner-control-types) If the individual passes the UBO threshold for the entity's incorporation country, they are automatically recorded as a beneficial owner. ### Corporate shareholder For a corporate shareholder, pick another entity from the same workspace and provide: * **Ownership percentage** (set to **0** to record a control-only relationship — see [Control-only corporate shareholders](#control-only-corporate-shareholders)) * **Relationship type** — Parent, Investor, or Other * **Stock class** (optional) * **Significant control** (optional) — toggle on if the corporate shareholder exercises significant control over this entity * **Inherited UBOs** — pick which of the parent's UBOs should propagate down as indirect UBOs of this entity #### Selecting inherited UBOs When a corporate entity becomes a shareholder, you choose explicitly which of its UBOs propagate down as indirect UBOs of the entity below. The picker lists every UBO recorded against the parent entity; tick the ones that should also be UBOs of this entity. Leaving the list empty propagates no UBOs — the corporate shareholder still appears as a shareholder, but none of its UBOs become indirect UBOs of this entity. For each inherited UBO you can override the [control type](#beneficial-owner-control-types) — for example, to mark a parent's founder as exercising "Other significant control" rather than "Indirect ownership" for this entity. Ownership cycles are rejected at write time. You cannot, for example, make Entity A a shareholder of Entity B if Entity B is already a direct or indirect shareholder of Entity A. ## Control-only UBOs Some individuals control an entity without holding any equity — for example, a person who can appoint or remove the majority of the board. To record this: 1. Click **Add shareholder** → **Individual**. 2. Enter their details and set **Ownership percentage** to **0**. 3. Toggle **Has significant control** on and pick a **Control type**. The person appears in the **Ultimate beneficial owners** section but not in the **Shareholders** list, since they hold no equity. ### Control-only corporate shareholders A corporate entity can also exercise significant control without holding equity — for example, a holding company that has board appointment rights over a sister entity. To record this, add the corporate shareholder with **Ownership percentage** set to **0** and **Significant control** toggled on. The link appears as a dashed edge on the [Corporate structure](/product/entities/corporate-structure) org chart to distinguish it from equity ownership. ## Beneficial owner control types Each UBO is tagged with the basis on which they qualify. Commenda supports the control types most commonly required by global beneficial ownership registers: * **Direct ownership** — the person directly owns shares above the threshold * **Indirect ownership** — the person owns the entity through one or more intermediate corporate shareholders * **Other significant control** — non-equity control (e.g. board appointment rights, voting trusts) Click any UBO to open their detail panel, where you can review their address, nationality, date of birth, masked SSN (last four digits only), and the roles they hold across the entity (director, officer, shareholder, UBO, authorized signatory). For inherited UBOs, the panel shows the path of corporate shareholders through which they own the entity. You can edit or delete a UBO that came from a direct individual shareholding, but **inherited UBOs** can only be changed by editing the parent corporate shareholder. This keeps the inheritance graph consistent. ## UBO thresholds The UBO threshold is the minimum ownership percentage at which a person is treated as a beneficial owner. Commenda applies the threshold for the entity's **country of incorporation** — for example: * 25% for most EU countries, the United States, the United Kingdom, Canada, and Australia * 10% for India, Chile, Argentina, and many Caribbean jurisdictions * 5% for Colombia, Ghana, Nigeria, and South Africa * Any positive ownership for Ecuador and Guatemala Thresholds are applied automatically — you do not need to configure them per entity. ## Stock classes If an entity has multiple classes of stock (Common, Preferred Series A, etc.), you can define each class on the entity and assign it to individual shareholdings. Each stock class has: * **Class name** (e.g. "Common", "Preferred Series A") * **Type** (Common or Preferred) Stock classes are created and listed per entity. Once a class exists on an entity, it appears in the **Stock class** dropdown when adding or editing a shareholder on that entity. Classes that are still attached to a shareholding cannot be deleted — reassign or remove the shareholdings first. ## Non-controlled entities and ownership If a corporate shareholder is a [non-controlled entity](/product/entities/creating-entities#adding-an-existing-entity), it still appears as a shareholder of the entity below and is included in the [Corporate structure](/product/entities/corporate-structure) org chart. However, Commenda does not walk through a non-controlled parent when computing inherited UBOs — only ownership through entities you control contributes to the indirect-ownership UBO calculation. This keeps reporting focused on the people and entities you actually manage. ## Editing and removing shareholders Use the row actions on each shareholder to update or remove them. * **Editing an individual** to 0% ownership requires **Significant control** to be on; otherwise the person no longer qualifies as a shareholder or a UBO and you should **Remove** them instead. * **Editing a corporate shareholder** to 0% is allowed only when **Significant control** is on (a [control-only corporate shareholder](#control-only-corporate-shareholders)). Otherwise, remove the corporate shareholder if it no longer holds equity. * **Removing a shareholder** also removes any UBOs that only existed because of that shareholding. Inherited UBOs from other branches are preserved. * **Inherited UBOs** cannot be edited or removed directly — change them by editing the parent corporate shareholder's inherited-UBO selection. ## Exporting an ownership summary Click **Export** on the Ownership tab to download a PDF summary of the entity's ownership and control. The document includes: * A cover page with entity name, incorporation country, and report date * The full shareholder register with ownership percentages and stock classes * All ultimate beneficial owners with their control type and source * Snapshot metadata so the report is suitable for sharing with banks, auditors, and regulators The PDF contains every shareholder and UBO regardless of pagination on screen. ## Org structure view For companies with multiple related entities, open the **Corporate structure** view to see the full ownership graph as a diagram. See [Corporate structure](/product/entities/corporate-structure) for details. # Philippines Source: https://docs.commenda.io/product/entities/philippines Supported entity types, required documents, and tax registrations for Philippine business entities on Commenda. Commenda supports nine entity types in the Philippines, covering corporations, partnerships, branch offices, and nonprofit structures. When you add or manage a Philippine entity, Commenda automatically applies the correct document, registration, and government identifier requirements based on the entity type you select. ## Supported entity types | Entity type | Description | Ownership | | -------------------------------- | ---------------------------------------------------------------------------------------- | ----------------- | | **Domestic Corporation** | Standard stock corporation incorporated under the Revised Corporation Code | Limited by shares | | **Stock Corporation** | Corporation with authorized capital stock and share-based ownership | Limited by shares | | **Close Corporation** | Corporation with share transfer restrictions and a limited number of shareholders | Limited by shares | | **One Person Corporation (OPC)** | Single-stockholder corporation (distinct from India's OPC) | Limited by shares | | **Partnership** | General or professional partnership registered with the SEC | Partnership | | **Branch Office** | Philippine branch of a foreign corporation operating under an SEC license | Not applicable | | **Non-Stock Corporation** | Corporation without authorized capital stock, typically for civic or charitable purposes | Not applicable | | **Educational Corporation** | Corporation organized for educational purposes | Not applicable | | **Religious Corporation** | Corporation organized for religious purposes | Not applicable | ## Industry classification Philippine entities use the **PSIC** (Philippine Standard Industrial Classification) code system. PSIC codes are 4 to 5 digits and are required during entity setup. ## Required documents Commenda tracks the documents each entity type must maintain. The specific set varies by entity type, but all Philippine entities require a common base of tax and compliance documents. ### Formation documents | Document | Applies to | | --------------------------------------------------- | --------------------- | | Articles of Incorporation and by-laws | All corporation types | | Certificate of Incorporation | All corporation types | | Articles of Partnership | Partnership | | Certificate of Recording of Articles of Partnership | Partnership | | Head Office Articles of Incorporation | Branch Office | | SEC License to Do Business | Branch Office | ### Tax and compliance documents These documents are required across all Philippine entity types: | Document | Renewable | | ------------------------------------------------------------------ | --------- | | BIR Certificate of Registration (Form 2303) — income tax | No | | BIR Certificate of Registration (Form 2303) — employer withholding | No | | Barangay Clearance | Yes | | Mayor's / Business Permit | Yes | | VAT Registration (BIR Form 2303) | No | ### Ongoing administration documents | Document | Renewable | | ------------------------------- | --------- | | Audited Financial Statements | Yes | | General Information Sheet (GIS) | Yes | | Proof of Registered Address | Yes | | SEC Corporate Register Extract | Yes | Partnership entities do not require a General Information Sheet. ## Tax registrations Every Philippine entity must register with the Bureau of Internal Revenue (BIR). Commenda tracks four registration types for each entity: | Registration | Authority | Description | | --------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | **Tax Identification Number (TIN)** | BIR | 9-digit base with optional 3-digit branch code (e.g., `000-123-456-000`). Issued via BIR Form 1903; confirmed on BIR Form 2303. | | **VAT Registration** | BIR | Uses the entity TIN with branch code. Required for entities meeting the VAT threshold. | | **Employer Withholding Registration** | BIR | BIR registration for employer withholding tax on compensation. Separate SSS, PhilHealth, and Pag-IBIG employer registrations are also required. | | **Entity Formation (SEC Registration)** | SEC | Registration number issued by the Securities and Exchange Commission upon incorporation or recording of partnership articles. | For partnerships, the tax treatment depends on the type. General partnerships are taxed as corporations under NIRC §27(A). General Professional Partnerships (GPPs) are tax-transparent under NIRC §26 — partners are taxed individually. ## Getting started To add a Philippine entity in Commenda: 1. Go to **Entities** and click **Add entity**. 2. Select **Philippines** as the country. 3. Choose the appropriate entity type from the list above. 4. Enter the PSIC industry code and complete the required fields. Commenda will automatically generate the applicable document checklist and registration requirements for your entity type. # Registrations Source: https://docs.commenda.io/product/entities/registrations Track tax registrations, business licenses, and government IDs for your entities. The **Registrations** tab tracks where each entity is registered with government authorities and the status of each registration. ## Types of registrations * **Tax registrations** — sales tax, income tax, payroll tax, VAT * **Business registrations** — state registrations, business licenses * **Employer registrations** — EIN, employer accounts * **Other government IDs** — DUNS number, NAICS code, etc. ## Viewing registrations 1. Go to **Entities** and select an entity. 2. Click the **Registrations** tab. Each registration shows: * The authority and jurisdiction * Registration number or ID * Status (pending, active, inactive) * Filing frequency (if applicable) ## Adding a registration Click **Add registration** and provide the registration details. You can upload supporting documents (registration certificates, confirmation letters) directly to the registration record. ## Credentials For registrations that require login credentials (e.g., state tax portal accounts), Commenda securely stores these credentials. Only authorized team members can view or use them. Credentials are encrypted and stored securely. Never share login credentials outside of Commenda's secure credential storage. # Service guarantees Source: https://docs.commenda.io/product/indirect-tax/guarantees Internal reference for accuracy and on-time filing guarantees ## Overview Commenda provides two service guarantees for indirect tax services: the **Accuracy Guarantee** and the **On-Time Filing Guarantee**. These guarantees protect customers from financial exposure due to Commenda errors, subject to specific conditions and caps. Both guarantees are capped at the **Rolling ACV** — the fees the customer paid to Commenda for Services during the twelve (12) months preceding the tax period at issue. ## Accuracy guarantee ### What's covered If the customer properly configures and uses the Services and Commenda's tax calculation, rate, or taxability determination is inaccurate such that the return is filed incorrectly and a tax authority assesses uncollected sales tax, penalties, or interest (collectively, "Tax Shortfall"), Commenda will reimburse or credit the customer for the Tax Shortfall. ### Coverage cap Reimbursement is capped at the **Rolling ACV** — the fees the customer paid to Commenda during the twelve (12) months preceding the tax period at issue. ### Process #### Step 1: Customer receives assessment notice Customer receives a notice from a tax authority assessing uncollected sales tax, penalties, or interest due to an inaccuracy in Commenda's tax calculation, rate, or taxability determination. #### Step 2: Customer notifies Commenda (within 14 days) Customer must notify Commenda in writing within **fourteen (14) days** after receiving the first notice of assessment. **Required information:** * Copy of the assessment notice * Tax period(s) affected * Jurisdiction(s) involved * Amount assessed (tax, penalties, interest) * Description of the transactions at issue **Notification channel:** * Email: \[support contact] * Subject line: "Accuracy Guarantee Claim - \[Company Name]" * All required documentation attached #### Step 3: Customer cooperation with investigation Customer must provide all relevant information and reasonably cooperate with Commenda's investigation and any effort to contest or mitigate the assessment. **This includes:** * Transaction data and records * Configuration settings used * Communication with tax authority * Supporting documentation requested by Commenda * Participation in calls or meetings as needed * Authorization for Commenda to communicate with tax authority (if needed) #### Step 4: Commenda investigation Commenda will: * Review the assessment and underlying transactions * Verify whether the error was due to Commenda's calculation, rate, or taxability determination * Determine if all guarantee conditions are met * Assess whether the assessment can be contested or mitigated * Calculate the covered amount (up to Rolling ACV cap) #### Step 5: Resolution If the guarantee applies, Commenda will: * Reimburse the customer for the covered Tax Shortfall, or * Apply a credit to the customer's account for the covered amount **Timeline:** Commenda will make a determination and provide reimbursement or credit within a reasonable timeframe after completing the investigation. ### What's NOT covered The Accuracy Guarantee does not apply to errors caused by: #### 1. Customer's incorrect or incomplete data or configurations **Examples:** * Wrong addresses provided * Incorrect product taxability mappings * Missing or invalid exemption certificates * Incorrect registration threshold settings * Wrong customer classifications * Incomplete transaction data **Rationale:** Commenda's calculations are only as accurate as the data provided. Incorrect information or misconfigured systems shift responsibility to the customer. #### 2. Legal positions or classifications selected by customer **Examples:** * Customer chooses to treat a product as non-taxable when it's actually taxable * Customer selects a specific tax treatment based on their legal interpretation * Customer decides not to collect tax in a jurisdiction where they've exceeded the registration threshold * Customer applies an exemption based on their legal position **Rationale:** When customers make legal or classification decisions, they own the outcome. Commenda provides tools and guidance, but ultimate responsibility for legal positions rests with the customer. #### 3. Changes in law after the transaction date **Examples:** * Tax rate increases after transaction but before filing * New taxability rules enacted retroactively * Jurisdiction changes sourcing rules * New exemption requirements imposed **Rationale:** Commenda maintains current tax content but cannot predict or be responsible for retroactive legal changes. #### 4. Events outside Commenda's reasonable control **Examples:** * Third-party service failures (geocoding, address validation) * Force majeure events * Customer's system failures affecting data transmission * Tax authority system errors * Jurisdiction provides incorrect guidance **Rationale:** Commenda cannot guarantee against events beyond reasonable control. ### Sole and exclusive remedy The remedies in the Accuracy Guarantee are the customer's sole and exclusive remedies for inaccuracies in tax calculations or content. This means: * Customer cannot seek additional damages beyond the Rolling ACV cap * Customer cannot pursue other legal remedies for covered inaccuracies * The guarantee represents the full extent of Commenda's liability for calculation errors ## On-time filing guarantee ### What's covered If the customer has met all their obligations and Commenda fails to file a sales tax return by its statutory due date solely due to Commenda's error, Commenda will: 1. **Complete and submit the delinquent filing** at no additional charge 2. **Waive or refund any service fee** for that return 3. **Reimburse any late-filing penalties and interest** imposed by the tax authority, up to the Rolling ACV cap ### Coverage cap Reimbursement of penalties and interest is capped at the **Rolling ACV** — the fees the customer paid to Commenda during the twelve (12) months preceding the tax period at issue. ### Process #### Step 1: Missed deadline discovered Customer discovers that a return was not filed by its statutory due date, or receives a penalty notice from a tax authority for late filing. #### Step 2: Customer notifies Commenda (within 10 days) Customer must notify Commenda within **ten (10) days** of discovering the missed deadline or receiving a penalty notice to qualify for the guarantee. **Required information:** * Jurisdiction and tax type * Filing period * Statutory due date * Date customer discovered the issue or received penalty notice * Copy of penalty notice (if applicable) **Notification channel:** * Email: \[support contact] * Subject line: "On-Time Filing Guarantee Claim - \[Company Name]" * All required documentation attached #### Step 3: Commenda investigation Commenda will: * Verify the statutory due date * Review the filing timeline and any communications * Determine if the late filing was solely due to Commenda's error * Verify that the customer met all their obligations * Assess whether any exclusions apply #### Step 4: Resolution If the guarantee applies, Commenda will: 1. **Immediately file the delinquent return** (if not already filed) 2. **Waive or refund the service fee** for that return 3. **Reimburse the late-filing penalties and interest** (up to Rolling ACV cap) ### Customer obligations To qualify for the On-Time Filing Guarantee, the customer must have met all obligations: #### Timely data provision * Provide complete and accurate transaction data by agreed-upon deadlines * Respond to data quality issues or questions promptly * Ensure data feeds or integrations are functioning properly #### Sufficient funds * Maintain sufficient funds in account for tax remittance * Provide remittance authorization in advance of due dates * Respond to remittance issues promptly #### Required tax accounts * Maintain active tax registration accounts in all required jurisdictions * Provide Commenda with current login credentials or filing authorization * Notify Commenda of any account status changes #### Timely approvals * Review and approve returns by agreed-upon deadlines * Respond to questions or issues that require customer input * Provide necessary documentation when requested #### Accurate configuration * Maintain accurate registration threshold settings * Keep product taxability mappings current * Update exemption certificates as needed ### What's NOT covered The On-Time Filing Guarantee does not apply to late filings caused by: #### 1. Customer's delayed or inaccurate data **Examples:** * Transaction data provided after the deadline * Incomplete or incorrect transaction data requiring correction * Data quality issues that delay processing * Integration failures on customer's side **Rationale:** Commenda cannot file returns without complete, accurate data. Late data provision shifts responsibility to the customer. #### 2. Insufficient funds **Examples:** * Insufficient balance for tax remittance * Remittance authorization not provided * Remittance method declined or failed * Customer delays remittance approval **Rationale:** Returns cannot be filed without remittance. Ensuring sufficient funds is the customer's responsibility. #### 3. Failure to maintain required tax accounts **Examples:** * Tax registration account suspended or closed * Login credentials expired or invalid * Filing authorization revoked or expired * Account locked due to prior issues **Rationale:** Commenda cannot file to accounts that are not active and accessible. #### 4. Events outside Commenda's reasonable control **Examples:** * Tax authority system outages on filing deadline * Force majeure events * Third-party service failures * Jurisdiction changes filing requirements without notice **Rationale:** Commenda cannot guarantee against events beyond reasonable control. #### 5. Customer delays in approvals or responses **Examples:** * Return approval delayed past internal deadline * Questions or issues not addressed timely * Required documentation not provided * Customer unavailable during critical filing window **Rationale:** Filing deadlines require timely customer participation. Delays on the customer's end shift responsibility to them. ## Guarantee comparison | Feature | Accuracy guarantee | On-time filing guarantee | | ------------------------- | ------------------------------------------ | ------------------------------------------ | | **What's covered** | Tax Shortfall from inaccurate calculations | Late-filing penalties and interest | | **Coverage cap** | Rolling ACV | Rolling ACV | | **Notification deadline** | 14 days after first assessment notice | 10 days after discovering issue | | **Additional remedies** | Reimbursement or credit | Delinquent filing + fee waiver + penalties | | **Key exclusion** | Customer data/configuration errors | Customer delays or insufficient funds | | **Cooperation required** | Yes - investigation and mitigation | Yes - meeting all obligations | ## Maximizing guarantee protection ### For accuracy guarantee #### 1. Complete, accurate data * Verify addresses are correct and complete * Ensure product taxability mappings are accurate * Keep exemption certificates current * Maintain accurate registration threshold settings #### 2. Proper configuration * Follow Commenda's configuration guidance * Test configurations before going live * Review configuration regularly * Update settings when business changes #### 3. Documentation * Keep records of all transactions * Save configuration settings and changes * Document legal positions and decisions * Maintain audit trail #### 4. Prompt notification * Monitor for assessment notices * Notify Commenda within 14 days * Provide complete documentation * Respond to information requests quickly #### 5. Full cooperation * Participate in investigation * Provide requested information * Authorize Commenda to communicate with tax authority * Work collaboratively on mitigation ### For on-time filing guarantee #### 1. Meet all deadlines * Provide data by agreed-upon deadlines * Approve returns promptly * Respond to questions quickly * Don't delay critical decisions #### 2. Maintain account health * Keep sufficient funds available * Maintain active tax accounts * Keep credentials current * Monitor account status #### 3. Data quality * Validate data before submission * Address data quality issues promptly * Test integrations regularly * Monitor data feeds #### 4. Proactive communication * Notify Commenda of business changes * Report issues immediately * Respond to communications promptly * Keep contact information current #### 5. Plan ahead * Build buffer time before deadlines * Don't wait until last minute for approvals * Address issues early * Maintain backup remittance methods ## Common guarantee scenarios ### Scenario 1: Inaccurate rate applied **Situation:** Commenda applied a 7% rate when the correct rate was 8%. The tax authority assesses: * \$5,000 in uncollected tax * \$500 in penalties and interest **Guarantee applies?** Yes, if: * Customer provided correct address and transaction data * Customer properly configured the system * Customer notified within 14 days * Customer cooperated with investigation **Covered amount:** \$5,500 (tax + penalties + interest), up to Rolling ACV cap ### Scenario 2: Wrong product taxability **Situation:** Customer classified a product as non-taxable based on their legal interpretation. Tax authority disagrees and assesses \$10,000. **Guarantee applies?** No — this is a legal position selected by customer (exclusion #2) **Responsibility:** Customer owns the outcome of legal classification decisions ### Scenario 3: Late filing due to customer data delay **Situation:** Customer provided transaction data 3 days late. Commenda filed the return 2 days after the due date. Tax authority assesses \$200 in late-filing penalties. **Guarantee applies?** No — late filing was caused by customer's delayed data (exclusion #1) **Responsibility:** Customer is responsible for penalties due to their data delay ### Scenario 4: Late filing due to Commenda error **Situation:** Customer provided all data on time and approved the return 5 days before the due date. Commenda failed to submit the return due to an internal processing error. Tax authority assesses \$300 in penalties. **Guarantee applies?** Yes, if: * Customer met all obligations (timely data, approval, sufficient funds) * Customer notified within 10 days * Late filing was solely due to Commenda's error **Covered amount:** \$300 in penalties + fee waiver for that return, up to Rolling ACV cap ### Scenario 5: Incorrect address provided **Situation:** Customer provided a billing address instead of shipping address. Commenda calculated tax for the wrong jurisdiction. Tax authority assesses \$3,000 in uncollected tax. **Guarantee applies?** No — this is customer's incorrect data (exclusion #1) **Responsibility:** Customer is responsible for providing correct addresses ### Scenario 6: Retroactive law change **Situation:** A jurisdiction retroactively changed a product's taxability. Commenda's calculation was correct at the time of transaction but is now deemed incorrect. Tax authority assesses \$8,000. **Guarantee applies?** No — this is a change in law after the transaction date (exclusion #3) **Responsibility:** Retroactive law changes are not covered by the guarantee ## FAQ ### What is "Rolling ACV"? Rolling ACV is the total fees the customer paid to Commenda for the Services during the twelve (12) months preceding the tax period at issue. This is the cap for both guarantees. **Example:** If the tax period at issue is Q2 2024, Rolling ACV is the fees paid from Q2 2023 through Q1 2024. ### Can the customer get more than Rolling ACV in coverage? No. Both guarantees are capped at Rolling ACV. This is the maximum recovery under either guarantee. ### What if the customer disagrees with Commenda's determination? If the customer believes the guarantee should apply but Commenda determines it doesn't: 1. Provide a detailed explanation of the determination 2. Request any additional information that supports their position 3. Escalate to executive team if needed 4. Review the service agreement for dispute resolution procedures ### Do the guarantees cover state income tax or other taxes? No. These guarantees specifically cover sales tax (indirect tax) services only. They do not cover income tax, payroll tax, or other tax types. ### What if multiple issues occur in the same period? Each issue is evaluated separately. However, the total recovery across all issues is still capped at Rolling ACV for that period. ### How long does the investigation take? Investigation timelines vary based on complexity. Commenda will: * Acknowledge the claim within 2 business days * Provide initial assessment within 10 business days * Complete investigation within 30 days (for most cases) * Communicate timeline if more time is needed ### What if the tax authority is wrong? If Commenda believes the tax authority's assessment is incorrect: * Work with the customer to contest the assessment * Provide supporting documentation and analysis * Participate in appeals or protests (as appropriate) * Help minimize or eliminate the assessment If the assessment is successfully reduced or eliminated, the guarantee covers only the final assessed amount. ### Can the customer purchase additional coverage? The guarantees are included with the service agreement and cannot be increased beyond Rolling ACV. Options to consider: * Maintaining their own tax liability insurance * Increasing Rolling ACV by using more Commenda services * Working with their insurance broker on additional coverage ### What happens if Commenda goes out of business? The guarantees are only valid while Commenda is operating. Customers should consider: * Maintaining their own documentation and records * Having backup tax service providers identified * Maintaining tax liability insurance * Keeping sufficient reserves for potential tax liabilities ## Best practices for guarantee claims ### Do's * **Notify promptly** — Don't wait until the deadline * **Provide complete documentation** — Include everything requested * **Cooperate fully** — Respond quickly to information requests * **Document everything** — Keep records of all communications * **Be professional** — Work collaboratively with Commenda * **Follow up** — Check on status if there's no response ### Don'ts * **Don't delay notification** — Missing the deadline disqualifies the claim * **Don't withhold information** — Full disclosure is required * **Don't ignore requests** — Lack of cooperation can disqualify the claim * **Don't make assumptions** — Ask questions if unsure * **Don't escalate prematurely** — Give the process time to work * **Don't agree to settlements** — Consult with Commenda before agreeing to anything with tax authority ## Related documentation * [Incident Response SOP](/product/indirect-tax/incident-response-sop/overview) — How Commenda handles tax incidents * [Scenario classification](/product/indirect-tax/incident-response-sop/scenarios) — Types of tax issues and remedies * [Communication templates](/product/indirect-tax/incident-response-sop/templates) — Templates for customer communications # Exemptions Source: https://docs.commenda.io/product/sales-tax/exemptions Collect and manage tax exemption certificates from your customers. The **Exemptions** tab helps you collect, store, review, and track exemption certificates from customers who are exempt from indirect tax. ## Why exemption certificates matter When a customer claims they are tax-exempt (for example, a reseller, government agency, or nonprofit), you need a valid exemption certificate on file to justify not collecting tax. Commenda helps you manage this process. ## Viewing exemptions Go to **Indirect Tax** and select an entity, then click the **Exemptions** tab to see all certificates on file. ## Collecting certificates You can collect exemption certificates in two ways: ### Exemption portal Commenda provides a dedicated exemption portal where your customers can submit their certificates directly: 1. Send your customer the exemption portal link. 2. They fill in their details and upload their certificate. 3. The certificate appears in your Exemptions tab for review. ### Manual upload 1. Click **Add exemption certificate**. 2. Enter the customer details and exemption information. 3. Upload a copy of the certificate. ## Certificate details Each exemption certificate tracks: * **Customer name** and contact information * **Exemption type** (resale, government, nonprofit, etc.) * **Jurisdictions covered** — which states the exemption applies to * **Expiration date** — when the certificate expires * **Status** - approved, rejected, expired, or pending review ## Applying exemptions to transactions When a transaction is linked to a customer with active jurisdiction exemptions on file, Commenda automatically adjusts the tax. Commenda flags transactions with applied exemptions in your transaction list. Set up reminders for expiring exemption certificates so you can request renewals before they lapse. # Filings Source: https://docs.commenda.io/product/sales-tax/filings Prepare and track your indirect tax returns. The **Filings** tab helps you prepare, review, and track your indirect tax returns across all registered jurisdictions. ## Viewing filings Go to **Indirect Tax** and select an entity, then click the **Filings** tab. You'll see a list of all filings organized by period and jurisdiction. Each filing shows: * **Period** — the month, quarter, or year the filing covers * **Jurisdiction** — the state or region * **Due date** — when the return must be filed * **Status** — draft, ready to file, filed, or overdue * **Amount** — the total tax due ## Filing calendar Commenda generates filings automatically from your active registrations. The calendar uses each registration's filing frequency (monthly, quarterly, annual) to project the set of filings due for a jurisdiction over a given window. Before generation, your advisor can preview the calendar to see exactly which filings will be created for the selected period — including the start date, end date, and due date of each one. Generating the calendar: * Creates a filing row for every projected period. * Writes the jurisdiction's country and state onto the filing so it shows up alongside V1 filings in your list. * Opens a service request per filing in **ACTIVE**, **OVERDUE**, or **FILED** state so the task workflow below is ready to start. If a registration's frequency changes (for example, a state moves you from quarterly to monthly), the change is captured in the **Frequency change logs** so you can audit when and why the cadence shifted. ## Filing workflow Each filing moves through a three-step task sequence that coordinates work between your Commenda advisor and your team. The tasks appear on the filing's service request so you can track progress and see what's blocking next steps. Your Commenda advisor generates the draft filing report and verifies the aggregated totals against the connected transactions. This task is assigned to the agent and must complete before the next step unlocks. Once the draft is ready, this task is assigned to you. Open the filing to check the transaction list, totals, and any flagged items. Approve the data to hand the filing back to your advisor. Your advisor submits the return to the tax authority and then confirms the submission on Commenda. The filing status updates to **Filed** once this final task is complete. Each step only becomes actionable when the previous one completes — for example, you can't start reviewing transactions until the agent has generated the filing report, and the agent can't confirm submission until your review is done. ## Working on a filing Opening a filing gives you everything you need to review, sign off, and keep records in one place. * **Transaction summary** — aggregated totals (gross sales, taxable amount, tax collected) computed from the transactions attached to the filing period. * **Prepayments** — any prepayments recorded against the filing, shown alongside the net amount still due. * **Documents** — upload evidence, returns, or supporting files directly onto the filing. Uploaded documents stay attached to the filing and can be forwarded to collaborators from the chat room. * **Assignment** — advisors can assign a specific team member to a filing so it's clear who owns the next action. * **Lock / unlock** — when a filing is ready for review, advisors lock it to freeze the numbers. Unlocking is available if transactions or prepayments need to be corrected before submission. ### Exporting tax breakdowns From a filing you can export the full tax breakdown for downstream reporting or reconciliation: * A single-period breakdown for the filing you're viewing. * A breakdown with every underlying line item, for audit-level detail. * A breakdown across a custom date range, useful when reconciling totals that don't align to a single filing period. Exports run asynchronously — Commenda returns a job reference and delivers the file once it's ready. ## EU filings For entities with European Union tax obligations, Commenda supports EU-specific filing formats and requirements. EU filings include additional fields for intra-community transactions and VAT reporting. ### Filing contributions Commenda automatically computes VAT return box values for EU and UK filings. These computed values — called **filing contributions** — map directly to the boxes on your tax return form (for example, box 81 on a German VAT return for domestic supplies at 19%). Filing contributions are generated automatically as part of the regular tax breakdown processing cycle. When your transactions are processed, Commenda: 1. **Validates invoices** — checks that all transactions attached to the filing have the required address data (for example, a ship-from address) and that any non-reporting-currency invoices have an available FX rate for their transaction date. Transactions that fail validation are flagged with an error code so you can correct them. 2. **Converts to reporting currency** — for multi-currency filings, converts each invoice's taxable, tax, and gross amounts from `invoice_currency` into the filing's reporting currency (for example, EUR for German returns, GBP for UK returns) using the invoice's transaction date. 3. **Aggregates transaction data** — groups transactions by origin country, destination country, transaction type (sale, return, refund), tax rate, product type, customer type, and remitter type. 4. **Evaluates box rules** — matches aggregated data against the content-defined rules for each box on the tax return. This includes netting sales and returns, and computing formula-based totals that reference other boxes. 5. **Writes results** — stores the computed values as filing contributions. Each re-run replaces previous results, so contributions always reflect the latest transaction data. This process supports: * **Country-level filings** — standard VAT returns for individual EU member states and the UK * **Union OSS filings** — one-stop shop returns that report per-member-state totals for cross-border B2C sales within the EU * **IOSS filings** — import one-stop shop returns for distance sales of low-value goods imported into the EU #### Supported EU countries Filing contributions are available for the following EU member states: | Country | VAT rate tiers | | ------------------- | ----------------------------------------------- | | Austria (AT) | Standard, reduced | | Belgium (BE) | Standard, reduced | | Bulgaria (BG) | Standard, reduced | | Croatia (HR) | Standard, reduced | | Cyprus (CY) | Standard, reduced | | Czech Republic (CZ) | Standard, reduced | | Denmark (DK) | Standard, reduced | | Finland (FI) | Standard, reduced | | France (FR) | Standard, reduced, super-reduced, extra-reduced | | Germany (DE) | Standard, reduced | | Greece (GR) | Standard, reduced | | Hungary (HU) | Standard, reduced | | Italy (IT) | Standard, reduced, super-reduced, extra-reduced | | Lithuania (LT) | Standard, reduced | | Luxembourg (LU) | Standard, reduced, super-reduced, extra-reduced | | Latvia (LV) | Standard, reduced | | Malta (MT) | Standard, reduced | | Poland (PL) | Standard, reduced | | Portugal (PT) | Standard, reduced | | Romania (RO) | Standard, reduced | | Slovakia (SK) | Standard, reduced | | Slovenia (SI) | Standard, reduced | | Spain (ES) | Standard, reduced | Each country includes box rules for domestic sales, domestic purchases, intra-community sales and acquisitions, zero-rated domestic sales, imports, exports, and total output VAT. Sales and returns are automatically netted within each box. To view the computed contributions for a filing, click on the filing to open its detail view. You can also retrieve contributions programmatically using the [filing contributions API endpoint](/engine/indirect-tax/filings/filings-contributions-GET). Filing contributions are recomputed each time the automated processing cycle runs. If you add or update transactions after contributions have been generated, the next processing cycle updates the contributions to reflect the changes. #### Multi-currency filings When a filing's transactions are recorded in different currencies than the filing's reporting currency (for example, USD or GBP invoices on a German EUR return), Commenda converts each transaction's taxable amount, tax amount, and gross amount into the reporting currency using the FX rate published for the transaction's date. Single-currency filings — where every invoice is already in the reporting currency — are unaffected and produce the same numbers as before. If an FX rate is missing for any transaction's date, the contribution sync for that filing fails. Each affected invoice is flagged with `TRANSACTION.CURRENCY.FX_RATE_UNAVAILABLE`, and no contribution values are written until the rate is backfilled and processing re-runs. This prevents accidentally submitting a return that omits legitimate revenue. The job's success and failure counts reflect the number of affected versus unaffected invoices, so you can see at a glance how many transactions need attention. The FX conversion behavior described above applies to EU and UK V2 filings. US and Canadian filings use a separate calculation flow and are not affected. Always verify your filing amounts before submission. Once you file a return with the tax authority, corrections may require amended returns. # Getting started with indirect tax Source: https://docs.commenda.io/product/sales-tax/getting-started Set up indirect tax tracking for your entities in Commenda. This page walks you through the initial setup of indirect tax tracking for your entities. ## Prerequisites Before setting up indirect tax, make sure you have: * At least one entity added to your Commenda account * Your entity's business details filled in (EIN, addresses, etc.) ## Initial setup Click **Indirect Tax** in the sidebar. If you have multiple entities, select the entity you want to set up. Fill in additional details required for indirect tax purposes, such as your business type, NAICS code, and physical locations. Choose your tax configuration: * **Tax-inclusive pricing** — your prices already include tax * **Tax-exclusive pricing** — tax is added on top of your prices * **Filing frequency** — how often you file (monthly, quarterly, annually) Add your existing indirect tax registrations or start the process of registering in new jurisdictions. Connect your accounting software through Commenda's integrations or upload transaction data via CSV. ## Connecting accounting software The fastest way to get started is to connect your accounting software. Commenda integrates with QuickBooks, Xero, NetSuite, Zoho Books, Stripe, Shopify, WooCommerce, and more. See [Supported integrations](/integrations/supported-integrations) for the full list and setup instructions. ## Uploading transactions manually If you prefer not to connect your accounting software, you can upload transaction data via CSV. Go to **Indirect Tax > Transactions** and click **Upload CSV** to import your data. # Indirect tax Source: https://docs.commenda.io/product/sales-tax/overview Manage indirect tax registrations, transactions, filings, and exemptions across all your jurisdictions. Commenda's indirect tax module helps you manage the full lifecycle of indirect tax compliance — from determining where you've exceeded registration thresholds, to registering, tracking transactions, managing exemptions, and filing returns. ## Key features Track where you're registered for indirect tax and manage your registration status. Import and track taxable transactions from your accounting software or CSV files. Manage your indirect tax returns and track filing deadlines. Collect and manage exemption certificates from your customers. Classify your products and services for accurate tax calculation. Calculate indirect tax for specific transactions. ## How it works Commenda helps you identify where your business has exceeded registration thresholds based on your registrations, locations, and transaction data. Register for indirect tax in jurisdictions where you've exceeded the threshold. Commenda can help you through the registration process. Connect your accounting software or upload transaction data to track taxable sales. Collect, review, and track exemption certificates from tax-exempt customers. Prepare and file your indirect tax returns on time with deadline tracking and filing management. ## Getting started If you're new to indirect tax on Commenda, follow the [Setting up indirect tax](/guides/setting-up-sales-tax) walkthrough for a step-by-step guide. # Products Source: https://docs.commenda.io/product/sales-tax/products Classify your products and services for accurate indirect tax calculation. The **Products** tab lets you classify what you sell so Commenda can determine the correct tax treatment for each product or service in each jurisdiction. ## Why product classification matters Different products and services are taxed differently depending on the jurisdiction. For example: * Software may be taxable in one state but exempt in another * Food products may have a reduced rate * Professional services may not be subject to indirect tax By classifying your products, Commenda can automatically apply the correct tax rates. ## Managing products Go to **Indirect Tax** and click the **Products** tab to view and manage your product catalog. For each product, you can set: * **Product name** — a descriptive name * **Product category** — the type of product or service * **Tax code** — the specific tax classification * **Description** — additional details ## Adding products Click **Add product** to create a new product classification. If you've connected your accounting software, Commenda may automatically import products from your existing catalog. # Indirect tax registrations Source: https://docs.commenda.io/product/sales-tax/registrations Manage your indirect tax registrations across states and jurisdictions. The **Registrations** tab tracks where each entity is registered to collect and remit indirect tax. ## Viewing registrations Go to **Indirect Tax** and select an entity, then click the **Registrations** tab. You'll see all current registrations with: * **State / Jurisdiction** — where you're registered * **Registration number** — your tax ID * **Status** — active, pending, or inactive * **Filing frequency** — monthly, quarterly, or annually * **Effective date** — when the registration became active ## Adding a registration If you're already registered in a jurisdiction: 1. Click **Add registration**. 2. Select the state or jurisdiction. 3. Enter your registration number and effective date. 4. Set the filing frequency. ## Requesting a new registration If you need to register in a new jurisdiction: 1. Click **Request new registration**. 2. Select the state or jurisdiction. 3. Provide the required details (business information, officer details). 4. Commenda creates a service request to handle the registration process. Registration requirements vary by jurisdiction. Commenda's team will guide you through the specific requirements for each one. ## Local jurisdictions Some jurisdictions have local sub-regions (cities, counties, districts) with their own indirect tax requirements. You can add local registrations under each primary registration. ## Managing credentials Tax portals often require login credentials for filing. Commenda securely stores these credentials so your team or advisor can file on your behalf. # Tax calculator Source: https://docs.commenda.io/product/sales-tax/tax-calculator Calculate indirect tax for specific transactions or scenarios. The **Tax calculator** is a tool for calculating the indirect tax on a specific transaction or testing tax rates for different scenarios. ## Using the calculator Go to **Indirect Tax** and select an entity, then click **Tax calculator**. Enter the following details: * **Ship-from address** — where the product ships from * **Ship-to address** — the customer's location * **Product** — what is being sold (select from your product catalog) * **Amount** — the transaction amount The calculator returns the applicable tax rate and total tax amount, broken down by jurisdiction (state, county, city, district). ## When to use the calculator * Quoting a customer and need to include tax * Verifying the tax rate for a specific jurisdiction * Testing how product classification affects the tax amount * Checking rates before entering a new market # Transactions Source: https://docs.commenda.io/product/sales-tax/transactions Import and manage taxable transactions for indirect tax compliance. The **Transactions** tab shows all your taxable transactions, which feed into your indirect tax filings and calculations. ## Data sources Transactions can come from two sources: 1. **Accounting software** — automatically synced from your connected accounting platform (QuickBooks, Xero, Stripe, Shopify, etc.) 2. **CSV upload** — manually uploaded from a spreadsheet ## Viewing transactions Go to **Indirect Tax** and select an entity, then click the **Transactions** tab. Each transaction shows: * **Date** — when the transaction occurred * **Customer** — who the sale was to * **Amount** — the transaction amount * **Tax amount** — the calculated tax * **Jurisdiction** — where the tax applies * **Filing status** — whether Commenda included the transaction in a filing ## Uploading transactions To upload transactions via CSV: Format your CSV with columns for date, customer, amount, and jurisdiction. Commenda provides a template you can download. Go to **Transactions** and click **Upload CSV**. Select your file. Map your CSV columns to Commenda's transaction fields. Review the imported transactions and confirm the upload. ## Transaction details Click any transaction to view its full details, including: * Line items and tax breakdown * Customer information * Exemption status (if the customer has a valid exemption certificate) * Filing assignment For the most accurate and up-to-date transaction data, connect your accounting software rather than uploading manually. # Incorporation Source: https://docs.commenda.io/product/services/incorporation Incorporate new business entities in supported countries through Commenda. Commenda supports incorporating new entities in multiple countries. The incorporation wizard guides you through the requirements for each jurisdiction and handles the filing on your behalf. ## Supported countries | Country | Entity types | | ------------------ | ------------------------------------- | | **United States** | C-Corp, LLC, S-Corp, Nonprofit | | **Canada** | Corporation | | **United Kingdom** | Ltd, LLP | | **Ireland** | Ltd | | **Singapore** | Pte Ltd | | **UAE** | PJSC, Free Zone Entity, Civil Company | | **India** | Private Limited, LLP | ## How it works Go to **Entities**, click **Add entity**, and select **Incorporate a new entity**. Select where you want to incorporate and the entity type. The incorporation wizard collects all required information for your chosen jurisdiction: * Entity name (and alternatives) * Registered address * Directors and officers * Share structure * Purpose of the entity * Additional jurisdiction-specific details Review all the information and submit the incorporation request. A service request is created to track the incorporation. You'll receive updates as the filing progresses. ## After incorporation Once your entity is incorporated, Commenda will: * Add the entity to your account with all the details from the filing * Upload formation documents to your document repository * Generate applicable compliance obligations in your compliance calendar * Set up any required registrations Incorporation timelines vary by country and jurisdiction. Your service request will include estimated completion dates. # Service marketplace Source: https://docs.commenda.io/product/services/marketplace Browse and purchase professional services from Commenda's network of vetted providers. The **Service marketplace** is where you can browse and purchase professional services for your entities. Services are provided by Commenda's in-house team and vetted external partners. ## Browsing services Go to **Services** in the sidebar to open the marketplace. Services are organized by country and category. ### Available service categories * **Incorporation** — form new entities in supported countries * **Tax filing** — income tax, franchise tax, annual reports * **Indirect tax** — registration, filing, and compliance * **Bookkeeping** — ongoing accounting and bookkeeping services * **Compliance** — regulatory filings, BOI reports, etc. * **Transfer pricing** — documentation and benchmarking studies * **Registered agent** — registered agent services by state * **Legal** — corporate governance, amendments, dissolutions ## Purchasing a service Browse the marketplace and click on the service you need. Some services have different pricing tiers or options. Select the variant that fits your needs. Enter the required information about your entity and the specific work needed. Review the pricing and details, then confirm your order. Once you purchase a service, Commenda automatically creates a service request so you can track the progress of the work. ## Service providers Services may be delivered by: * **Commenda in-house** — Commenda's own team * **Commenda advisors** — accounting professionals on the Commenda platform * **External vendors** — vetted third-party providers You'll always know who is handling your service and can communicate with them directly through the service request. # Services Source: https://docs.commenda.io/product/services/overview Browse, purchase, and track professional services through Commenda. Commenda connects you with vetted professional service providers for incorporation, tax filing, compliance, bookkeeping, and more. You can browse services in the marketplace, create service requests, and track the delivery of every engagement. Browse and purchase professional services. Track the progress of services being delivered. Incorporate new entities in supported countries. # Service requests Source: https://docs.commenda.io/product/services/service-requests Track the progress of services being delivered to you. A **service request** tracks a specific piece of work being done for your company — whether it's an incorporation filing, a tax return, or a compliance task. Service requests give you visibility into the progress, tasks, and communications for each engagement. ## Viewing service requests You can find your service requests in several places: * **Home dashboard** — active service requests appear on your home page * **Service request link** — click any service request notification or link * **Compliance calendar** — compliance items linked to service requests ## Service request details Each service request includes: * **Status** — not started, in progress, completed, or archived * **Tasks** — a list of individual tasks with assignees and statuses * **Documents** — files uploaded or generated as part of the work * **Chat** — a dedicated chat room for communication with the service team * **Timeline** — a history of all activity on the request ## Tasks Tasks within a service request are assigned to specific people: * **Client tasks** — things you or your team need to do (provide information, upload documents, approve something) * **Agent tasks** — things the service provider needs to do (file a document, review information) * **Admin tasks** — things Commenda's internal team handles Each task has a status: | Status | Meaning | | ------------------- | ---------------------------------- | | **Not started** | Work hasn't begun | | **In progress** | Someone is working on it | | **Action required** | Your input or action is needed | | **Completed** | The task is done | | **SLA breached** | The task has exceeded its deadline | ### Per-task assignees Client tasks can be assigned to a specific team member on your company. This lets you distribute work across your team instead of every client task defaulting to the same person. When members are first added to a service request, Commenda automatically assigns all existing client tasks to a default team member (prioritizing company admins). You can then reassign individual tasks to other team members as needed. Each task shows the assigned person's name and avatar, so everyone on the team can see who is responsible for what. When a task is reassigned, the new assignee receives an email notification. ## Pending on Each service request in your services list shows a **Pending on** indicator that tells you exactly who needs to act next to move the request forward. This makes it easy to scan a long list of services and immediately spot which ones are blocked on you versus which ones are with your agent or with Commenda. The indicator reflects the assignees of the service request's currently active tasks: * **In progress tasks** — if any tasks are in progress, Pending on lists everyone assigned to those tasks. Service requests can run multiple tasks in parallel, so you may see more than one name. * **Next not-started task** — if no tasks are in progress, Pending on shows the next not-started task's assignee, so you can see who is up next. The displayed assignee depends on the task's assignee type: | Task assignee type | Pending on shows | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Client** | The team member assigned to the task. If no specific assignee is set, the request's primary client contact is shown. Falls back to "Customer" when no user is available. | | **Agent** | The agent firm user assigned to the request. Falls back to the agent firm's name when no individual is assigned. Falls back to "Agent" when neither is available. | | **Admin** | Shown as "Commenda" — the request is with our internal team. | Names are deduplicated, so a person assigned to multiple parallel tasks only appears once. Filter or sort your services list by Pending on to quickly surface every request that's currently waiting on your team. ## Communication Each service request has a built-in chat room where you can communicate with the service team, ask questions, and share updates. You'll also receive notifications when tasks need your attention. Your chat list shows a preview of the most recent message for each service request, including the sender's name and a text snippet. This helps you quickly identify which conversations have new activity without opening each one individually. You can **pin** a service request chat to keep it at the top of your chat list. This is useful when you're actively working on a request and want quick access to its conversation. Pinning is personal — only you see your pinned chats. Check your Home dashboard regularly for service requests that need your attention. Tasks marked **Action required** are waiting on you. # Settings and team Source: https://docs.commenda.io/product/settings/overview Manage your company settings, team members, and account preferences. The **Settings** section is where you manage your company account, team members, and platform preferences. ## Accessing settings Click **Settings** at the bottom of the sidebar navigation. ## Team management You can invite team members to your Commenda account so they can access your entities, compliance calendar, and other features based on their role. ### Inviting team members Click **Settings** in the sidebar. Navigate to the team or members section. Click **Invite** and enter the person's email address and role. The invited person receives an email with a link to join your account. ### Managing existing members From the team management page, you can: * **Update name or role** — edit a member's display name or change their role between Company Admin and Company User * **Remove members** — revoke a person's access to your account * **View assignments** — see what each team member has access to Every company must keep at least one Company Admin. If a member is the only admin on the company, you cannot change their role to Company User until you promote another member to Company Admin first. Removing a team member immediately revokes their access to all company data. Make sure to reassign any tasks or responsibilities before removing someone. ## Roles and permissions Commenda uses role-based access control. See the [User roles](/introduction/user-roles) page for a full description of each role and their access levels. | Role | Access level | | ----------------- | --------------------------------------------------------------------------------- | | **Company Admin** | Full access to all company data, entities, and settings. Can manage team members. | | **Company User** | Full access to company data and entities. Cannot manage team members. | | **Accountant** | Access to financial data across entities. Designed for external advisors. | | **Controller** | Access limited to specific assigned entities. | | **Employee** | Limited access to their own payroll and equity information. | | **Custom** | Permissions defined on a per-user basis. | # E-signatures Source: https://docs.commenda.io/product/tools/esign Collect electronic signatures on documents using DocuSign integration. Commenda integrates with DocuSign to let you collect electronic signatures on documents directly from the platform. The eSign feature is available within service requests. ## How it works Navigate to a service request and click the kebab menu (three dots). Select **Request Signature**. Upload a new document or choose from documents already attached to the service request. Select from existing contacts associated with the service, or add new recipients by entering their name and email. You can add multiple recipients if the document requires signatures from multiple people. Using DocuSign's embedded interface, visually place signature fields, date fields, text fields, and other form elements on the document. Assign fields to specific recipients. Review the document and click **Send**. DocuSign sends email notifications to all recipients. ## Signature tasks When you send a document for signature, the system automatically creates one task per recipient. These tasks appear on the service page and Home screen. ### Task statuses | Status | Description | | ------------ | -------------------------------------------------------------------------------------------------------------- | | **Pending** | Recipient is waiting for notification, or waiting for a previous signer to complete (when using signing order) | | **Sent** | DocuSign has sent the email to the recipient | | **Viewed** | Recipient has opened the document | | **Signed** | Recipient has completed signing | | **Canceled** | You or an agent canceled the signature request | If you configure an explicit signing order (for example, Signer 1 must sign before Signer 2), subsequent signers remain in "Pending" status until the previous signer completes. Once the previous signer finishes, DocuSign updates the next signer's status to "Sent" and sends them an email notification. ## Managing signature requests ### Sending reminders You can send reminders to recipients who haven't signed yet by locating the signature task and clicking **Send Reminder**. * Maximum of 1 reminder per day per recipient * Both agents and clients can send reminders * If both send a reminder on the same day, the second attempt is suppressed ### Viewing signed documents Once a recipient signs, the task status updates to "Signed." Agents can download the signed document from the task card. Commenda stores the signed document with the service request. ### Canceling signature requests Agents can cancel signature requests that are in progress. When canceled: * Commenda voids all pending signatures * Recipients can no longer sign the document * Commenda marks all tasks as "Canceled" ## Signer experience When someone receives a document to sign: 1. They receive an email from DocuSign with a link to view and sign the document 2. They click the link and review the document 3. They complete the required signature fields and submit 4. No DocuSign account is required to sign Clients see signature tasks on their Commenda dashboard with the message "An email has been sent to " and an option to send a reminder. ## What happens after signing * When a recipient signs, the task status updates and you can download the signed document * If multiple signers are required, DocuSign automatically notifies the next recipient * When all recipients sign, Commenda marks the envelope as "Completed" ### When a recipient declines to sign If a recipient declines to sign: 1. **DocuSign automatically cancels the entire envelope** — it voids all signatures, not just the one that was declined 2. **Commenda marks all tasks as "Canceled"** — including recipients who haven't been notified yet 3. **Commenda records the decline reason** — the task description shows which recipient declined 4. **No further signatures are possible** — you must create a new signature request ## Notifications DocuSign's native notification service handles all signature-related notifications — not Commenda's notification system. This includes email reminders, confirmation emails, and completion notifications. The DocuSign integration is available to service providers and advisors. Contact your Commenda account manager for setup. # General thread Source: https://docs.commenda.io/product/tools/general-thread Use the company-wide general thread for communications that don't belong to a specific service request. The **General thread** is a persistent, company-wide chat for conversations that don't belong to a specific service request. Every company on Commenda gets one General thread — Commenda automatically creates it when your company is onboarded, and you cannot delete or duplicate it. ## When to use the general thread * Asking general questions to your advisor or Commenda team * Sharing updates that affect multiple entities or service requests * Discussing topics that don't fit into a specific compliance item or filing * Coordinating across your team * Posting company-wide announcements ## General thread vs. service request chat | | General thread | Service request chat | | ---------------- | -------------------------------------------- | -------------------------------------------- | | **Scope** | Company-wide | Specific to one service request | | **Participants** | All company team members and linked advisors | Only people involved in that service request | | **Use case** | General questions and coordination | Service-specific communication | | **Persistence** | Always available | Tied to the service request lifecycle | For questions about a specific filing or service, use the chat within that service request instead. It keeps the conversation in context and visible to the right people. ## Who can access it * **Company users** can view and send messages in their company's General thread * **Admins and account managers** can view and interact with General threads for companies they manage ## Message previews The General thread shows a preview of the last message directly in your chat list, so you can see recent activity at a glance without opening the thread. Each preview displays the sender's name and a snippet of their message. File-only messages appear as "\[sender] sent a file." ## Sending messages You can send messages in the General thread the same way you use chat in service requests: 1. Navigate to your company's General thread from the sidebar or communications section 2. Type your message in the input field 3. Press **Send** You can also: * **Pin the conversation** to keep the General thread at the top of your chat list for quick access * **Pin messages** to highlight important updates so they're easy to find later * **Mark messages as read** to track what you've reviewed ## Pinning conversations You can pin any chat room — including the General thread and service request chats — to keep it at the top of your chat list. This is helpful when you're actively working on something and want quick access without scrolling. * To pin a conversation, open the chat room and select **Pin** * To unpin it, open the pinned chat room and select **Unpin** Pinning is personal. Only you see your own pinned conversations — other team members' chat lists are not affected. ## Notifications When a new message is posted in the General thread, participants receive email notifications: * **Messages from Commenda's team** notify your company members with a link to the company portal * **Messages from your team** notify the assigned account managers with a link to the relevant company page Commenda only sends notifications for messages in the main customer channel. Internal notes between Commenda team members do not trigger notifications to you. # Benchmarking Source: https://docs.commenda.io/product/transfer-pricing/benchmarking Track benchmarking studies that support your transfer pricing decisions. **Benchmarking studies** provide evidence that your intercompany pricing is at arm's length by comparing your transactions to similar transactions between unrelated parties. ## Why benchmarking matters Tax authorities may challenge your transfer pricing if they believe intercompany transactions are not priced at arm's length. Benchmarking studies provide the economic analysis to support your pricing decisions. ## Tracking benchmarking studies Go to **Transfer Pricing** and click the **Benchmarking** tab to view and manage your studies. For each study, you can track: * **Scope** — which entities and transactions are covered * **Methodology** — the benchmarking approach used * **Results** — the arm's length range and where your pricing falls * **Date** — when the study was conducted * **Supporting documents** — the full benchmarking report and data ## Requesting a benchmarking study If you need a new benchmarking study, you can request one through Commenda's service marketplace. Professional advisors will conduct the analysis and deliver the results directly to your Commenda account. ## Generating a benchmark automatically For supported transaction types, you can generate a benchmarking study directly from a benchmark record instead of requesting one through the marketplace. Commenda submits the details of the intercompany transaction to our benchmarking provider, which returns an arm's length range based on comparable third-party data. Use automated generation when you want a faster, self-service benchmark and the transaction fits one of the supported categories below. For complex or unusual arrangements, the marketplace route with a human advisor is still recommended. ### Supported transaction types Pick the transaction type that best describes the intercompany arrangement between the service provider entity and the counterparty: * **Distribution** — one entity buys goods from a related entity and resells them. * **Manufacturing** — one entity manufactures goods for a related entity. * **Services** — one entity provides services (e.g., management, technical, support) to a related entity. * **Finance** — intercompany loans, cash pooling, or other financing arrangements. * **Royalty** — licensing of intellectual property between related entities. ### How it works Go to **Transfer Pricing** → **Benchmarking** and open the benchmark you want to generate a study for. Make sure the service provider and counterparty entities are set and the relevant fiscal year is selected. Select the transaction type that matches your intercompany arrangement. Commenda will prompt you for the details required for that category. Submit the request. Commenda sends the transaction details to the benchmarking provider and stores the request and response on the benchmark for audit. Once processing completes, the benchmark shows the generated arm's length range and comparable data. You can attach the generated report as supporting documentation. Each benchmark can be submitted for generation once successfully. If a submission fails due to missing or invalid inputs, fix the inputs and retry — previous failed attempts do not block a retry. If a submission has already succeeded, create a new benchmark record to run another study. Only the sub-object that matches the selected transaction type is required. For example, if you choose **distribution**, fill in the distribution details; do not submit unrelated sub-objects. Mismatched inputs are rejected before submission. # Transfer pricing Source: https://docs.commenda.io/product/transfer-pricing/overview Document and manage intercompany transactions and transfer pricing policies. If your company has related entities that transact with each other, transfer pricing rules require you to document that these transactions are conducted at arm's length. Commenda helps you manage this process. ## What is transfer pricing? Transfer pricing refers to the prices charged for goods, services, or intellectual property transferred between related entities (e.g., a parent company and its subsidiary). Tax authorities require these prices to be at "arm's length" — meaning they should be similar to what would be charged between unrelated parties. ## What Commenda helps with Create and manage transfer pricing policies that define how intercompany services are priced. Track benchmarking studies that support your pricing decisions. ## How it works Set up corporate relationships between your entities (parent-subsidiary, etc.) in the [corporate structure](/product/entities/corporate-structure) section. Connect your accounting software to automatically pull intercompany transaction data. Document your transfer pricing policies, including the services provided and pricing methodology. Record benchmarking studies that support your arm's length pricing. Transfer pricing documentation requirements vary by country. Commenda supports both local file and master file documentation approaches. # Transfer pricing policies Source: https://docs.commenda.io/product/transfer-pricing/policies Create and manage transfer pricing policies for intercompany transactions. A **transfer pricing policy** documents how a specific intercompany service is priced and the methodology used to ensure arm's length compliance. ## Viewing policies Go to **Transfer Pricing** in the sidebar and click the **Policies** tab to see all your transfer pricing policies. ## Creating a policy Click the **Add policy** button. Choose the **service provider** (the entity providing the service) and the **service recipient** (the entity receiving the service). Document what service is being provided (e.g., management services, IT support, shared R\&D). Define how the price is determined (cost plus, comparable uncontrolled price, transactional net margin, etc.). Upload supporting documents such as service agreements, invoices, and calculation workpapers. ## Policy details Each policy tracks: * **Service provider and recipient** — the two entities involved * **Service description** — what is being provided * **Pricing methodology** — how the transfer price is calculated * **Transaction amounts** — the financial details of the intercompany transactions * **Supporting documents** — agreements, calculations, and benchmarking studies