Vendor Taxation Update API
curl --request PATCH \
--url https://api.pazy.io/v1.0/vendor/:vendorId/taxationimport requests
url = "https://api.pazy.io/v1.0/vendor/:vendorId/taxation"
response = requests.patch(url)
print(response.text)const options = {method: 'PATCH'};
fetch('https://api.pazy.io/v1.0/vendor/:vendorId/taxation', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.pazy.io/v1.0/vendor/:vendorId/taxation",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.pazy.io/v1.0/vendor/:vendorId/taxation"
req, _ := http.NewRequest("PATCH", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://api.pazy.io/v1.0/vendor/:vendorId/taxation")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.pazy.io/v1.0/vendor/:vendorId/taxation")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
response = http.request(request)
puts response.read_bodyVendor APIs
Vendor Taxation Update API
Correct a GSTIN or PAN already recorded against a vendor
Vendor Taxation Update API
curl --request PATCH \
--url https://api.pazy.io/v1.0/vendor/:vendorId/taxationimport requests
url = "https://api.pazy.io/v1.0/vendor/:vendorId/taxation"
response = requests.patch(url)
print(response.text)const options = {method: 'PATCH'};
fetch('https://api.pazy.io/v1.0/vendor/:vendorId/taxation', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.pazy.io/v1.0/vendor/:vendorId/taxation",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.pazy.io/v1.0/vendor/:vendorId/taxation"
req, _ := http.NewRequest("PATCH", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://api.pazy.io/v1.0/vendor/:vendorId/taxation")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.pazy.io/v1.0/vendor/:vendorId/taxation")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
response = http.request(request)
puts response.read_bodyAuthentication
All requests require an API key in the request headers. Headers:Authorization: Api-Key YOUR_API_KEY
Content-Type: application/json
Request
Content-Type:application/json
Replaces a tax identifier the vendor already holds. The identifier being changed is selected by the type query parameter — a GSTIN or a PAN — and the body carries both the current value (oldValue) and its replacement (newValue).
oldValue is not optional bookkeeping: it identifies which record to update. A vendor can hold several GSTINs, so the value you are replacing is how Pazy picks the row. For PAN, oldValue acts as a confirmation check against the stored PAN. In both cases a mismatch rejects the request.
This endpoint edits in place — the identifier keeps its record, so anything already linked to it stays linked. To add a new identifier instead, use the Vendor Taxation Creation API.
Path Parameters
| Parameter | Type | Required | Constraints | Description |
|---|---|---|---|---|
vendorId | string | Yes | 1-100 characters | Slug / unique identifier of the vendor |
Query Parameters
| Parameter | Type | Required | Constraints | Description |
|---|---|---|---|---|
type | string | Yes | GSTIN or PAN | Which tax identifier is being updated |
Body Parameters
| Parameter | Type | Required | Constraints | Description |
|---|---|---|---|---|
oldValue | string | Yes | Non-empty; must match a value currently on the vendor | The tax identifier being replaced. Leading and trailing whitespace is trimmed. |
newValue | string | Yes | Non-empty; must be a valid GSTIN or PAN per type | The replacement value. Leading and trailing whitespace is trimmed. |
400 VALIDATION_ERROR — they are not silently ignored.
Values are matched case-sensitively against upper-case formats. Send
29ABCDE1234F1Z5, not 29abcde1234f1z5 — a lower-case newValue is rejected as an invalid format, and a lower-case oldValue will not match the stored record.Updating a GSTIN
type=GSTIN applies the following checks, in order. The first one that fails rejects the request and nothing is written.
| Check | Rejected with |
|---|---|
| Vendor exists in your organization | 404 VENDOR_NOT_FOUND |
| Caller is an admin / bookkeeper, or the vendor’s owner | 403 ACCESS_DENIED |
Vendor state is ACTIVE or APPROVAL_PENDING | 400 VALIDATION_ERROR — Vendor is not active |
newValue is a valid GSTIN format | 400 INVALID_GST_NUMBER |
newValue does not belong to your own business (it is not built on one of your organization’s PANs) | 400 VALIDATION_ERROR |
No other vendor in the organization already uses newValue | 400 DUPLICATE_GSTIN — Duplicate GSTIN |
This vendor does not already hold newValue | 400 DUPLICATE_GSTIN — GSTIN already exists for this vendor |
newValue carries the same PAN as the vendor’s existing GSTIN / PAN | 400 VALIDATION_ERROR |
oldValue matches a GSTIN currently on the vendor | 404 VENDOR_NOT_FOUND — Existing GSTIN not found for this vendor |
| The GSTIN being replaced is not used by any invoice or vendor advance | 400 VALIDATION_ERROR |
- The standard 15-character GSTIN —
^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[CDSZ][0-9A-Z]{1}$, for example29ABCDE1234F1Z5 - Any 15-character value beginning with
99, used for UIN-style registrations
A GSTIN that has already been used on an invoice or a vendor advance cannot be edited — those transactions carry the tax identity they were filed under, and rewriting it would change historical records. Add the correct GSTIN with the Vendor Taxation Creation API instead, and use it going forward.
Duplicate GSTIN is not raised for a GSTIN held by another vendor — the per-vendor check (GSTIN already exists for this vendor) always applies regardless.
Updating a PAN
type=PAN applies the same vendor, access, and state checks, then:
| Check | Rejected with |
|---|---|
newValue is a valid PAN format — ^[A-Z]{5}[0-9]{4}[A-Z]{1}$, for example ABCDE1234F | 400 INVALID_PAN_NUMBER |
newValue does not belong to your own business | 400 VALIDATION_ERROR |
| The vendor does not have a GSTIN | 400 VALIDATION_ERROR — PAN cannot be edited when vendor has a GSTIN |
| The vendor has a PAN on record | 404 VENDOR_NOT_FOUND — Existing PAN not found for this vendor |
oldValue equals the vendor’s current PAN | 400 VALIDATION_ERROR — oldValue does not match the vendor's current PAN |
Once a vendor has a GSTIN, its PAN is derived from that GSTIN and can no longer be edited on its own. Correct the GSTIN instead.
What Happens After the Write
Once the change is committed, Pazy runs a few follow-up steps:- Verification.
newValueis checked against the GST portal (for GSTIN) or the PAN service (for PAN), and the result is returned asisVerifiedin the response — and stored on the record, replacing the previous verification state. A value that cannot be verified is still saved. - Audit trail. An
UPDATEentry recording both the before and after values is written against the vendor with sourceAPI, visible through the Vendor Audit Trail API. - Accounting sync. If an accounting integration is connected, the changed tax identifier is pushed to it.
200 OK and the new value remains saved.
Code Examples
curl -X PATCH "https://api.pazy.io/v1.0/vendor/<vendorId>/taxation?type=GSTIN" \
-H "Authorization: Api-Key YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"oldValue": "29ABCDE1234F1Z5",
"newValue": "27ABCDE1234F1Z2"
}'
const response = await fetch(
'https://api.pazy.io/v1.0/vendor/<vendorId>/taxation?type=GSTIN',
{
method: 'PATCH',
headers: {
'Authorization': 'Api-Key YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
oldValue: '29ABCDE1234F1Z5',
newValue: '27ABCDE1234F1Z2'
})
}
);
const result = await response.json();
import requests
url = "https://api.pazy.io/v1.0/vendor/<vendorId>/taxation"
headers = {
"Authorization": "Api-Key YOUR_API_KEY",
"Content-Type": "application/json"
}
params = {"type": "GSTIN"}
payload = {
"oldValue": "29ABCDE1234F1Z5",
"newValue": "27ABCDE1234F1Z2"
}
response = requests.patch(url, headers=headers, params=params, json=payload)
result = response.json()
cURL
curl -X PATCH "https://api.pazy.io/v1.0/vendor/<vendorId>/taxation?type=PAN" \
-H "Authorization: Api-Key YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"oldValue": "ABCDE1234F",
"newValue": "ABCDE5678G"
}'
Success Response
HTTP Status:200 OK
Response Fields:
| Field | Type | Description |
|---|---|---|
ok | boolean | Indicates whether the request was successful |
data | object | Result of the operation |
data.message | string | Human-readable confirmation — GSTIN updated successfully or PAN updated successfully |
data.isVerified | boolean | true if newValue was verified with the source authority. For GSTIN this means the registration is active on the GST portal; for PAN it means the PAN was confirmed. false when verification failed or was unavailable — the new value is still saved. |
Response Example — GSTIN Updated
{
"ok": true,
"data": {
"message": "GSTIN updated successfully",
"isVerified": true
}
}
Response Example — PAN Updated, Not Verified
{
"ok": true,
"data": {
"message": "PAN updated successfully",
"isVerified": false
}
}
Error Responses
Invalid GSTIN Format
HTTP Status:400 Bad Request
{
"ok": false,
"error": {
"code": "INVALID_GST_NUMBER",
"message": "Invalid GST format for new value"
}
}
Invalid PAN Format
HTTP Status:400 Bad Request
{
"ok": false,
"error": {
"code": "INVALID_PAN_NUMBER",
"message": "Invalid PAN format for new value"
}
}
GSTIN Is in Use
Returned when the GSTIN being replaced is already referenced by an invoice or a vendor advance. HTTP Status:400 Bad Request
{
"ok": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The current GSTIN is being used by invoice or vendor advance and cannot be edited"
}
}
Duplicate GSTIN
Returned when another vendor in your organization already holdsnewValue, or when this vendor already holds it.
HTTP Status: 400 Bad Request
{
"ok": false,
"error": {
"code": "DUPLICATE_GSTIN",
"message": "Duplicate GSTIN"
}
}
{
"ok": false,
"error": {
"code": "DUPLICATE_GSTIN",
"message": "GSTIN already exists for this vendor"
}
}
PAN Mismatch
Returned whennewValue’s embedded PAN differs from the PAN of the identifiers the vendor already holds. A single vendor cannot span two PANs — create a separate vendor for the other legal entity.
HTTP Status: 400 Bad Request
{
"ok": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "New GSTIN must have the same PAN as the vendor's existing GSTIN/PAN"
}
}
oldValue Does Not Match
For type=GSTIN, the vendor holds no GSTIN equal to oldValue:
HTTP Status: 404 Not Found
{
"ok": false,
"error": {
"code": "VENDOR_NOT_FOUND",
"message": "Existing GSTIN not found for this vendor"
}
}
type=PAN, the vendor has no PAN at all:
HTTP Status: 404 Not Found
{
"ok": false,
"error": {
"code": "VENDOR_NOT_FOUND",
"message": "Existing PAN not found for this vendor"
}
}
type=PAN, the vendor has a PAN but it is not the one you sent:
HTTP Status: 400 Bad Request
{
"ok": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "oldValue does not match the vendor's current PAN"
}
}
PAN Cannot Be Edited
Returned when a PAN update is attempted on a vendor that has a GSTIN. HTTP Status:400 Bad Request
{
"ok": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "PAN cannot be edited when vendor has a GSTIN"
}
}
Tax Identifier Belongs to Your Own Business
Returned whennewValue resolves to one of your own organization’s PANs.
HTTP Status: 400 Bad Request
{
"ok": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "This GSTIN belongs to your own business, not the vendor's. Please enter the vendor's GSTIN."
}
}
Vendor Not Active
Returned when the vendor is in any state other thanACTIVE or APPROVAL_PENDING — for example a disabled vendor.
HTTP Status: 400 Bad Request
{
"ok": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Vendor is not active"
}
}
Validation Error
Returned before any processing when the request does not match the schema — a missing or unsupportedtype, a missing or empty oldValue / newValue, or an unknown property.
HTTP Status: 400 Bad Request
{
"ok": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed: newValue: must have required property 'newValue'"
}
}
{
"ok": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed: /type: must be equal to one of the allowed values"
}
}
Vendor Not Found
HTTP Status:404 Not Found
{
"ok": false,
"error": {
"code": "VENDOR_NOT_FOUND",
"message": "Vendor not found"
}
}
Access Denied
Returned when the caller is neither an admin / bookkeeper nor the vendor’s owner. HTTP Status:403 Forbidden
{
"ok": false,
"error": {
"code": "ACCESS_DENIED",
"message": "Access denied: You can only update vendors you own"
}
}
Authentication Errors
HTTP Status:401 Unauthorized
{
"ok": false,
"error": {
"code": "MISSING_CREDENTIALS",
"message": "Missing Credentials"
}
}
{
"ok": false,
"error": {
"code": "INVALID_API_KEY",
"message": "Invalid API Key"
}
}
Permission Errors
The API key must carry vendor update permission. HTTP Status:403 Forbidden
{
"ok": false,
"error": {
"code": "INSUFFICIENT_PERMISSIONS",
"message": "Permission check failed - PERMISSION_CHECK_FAILED"
}
}
Internal Error
Returned when the change could not be persisted. The write is a single transaction, so the old value is left intact and the call is safe to retry. HTTP Status:500 Internal Server Error
{
"ok": false,
"error": {
"code": "INTERNAL_ERROR",
"message": "Error while updating vendor taxation"
}
}
Best Practices
- Fetch the current GSTIN / PAN with the Vendor Details API and send it verbatim as
oldValue— it selects the record to change, and a stale value fails the request - Send both values in upper case — a lower-case
newValueis rejected as an invalid format, and a lower-caseoldValuewill not match - Use this endpoint to correct a mistake, not to onboard a new registration. To add another GSTIN, use the Vendor Taxation Creation API
- Expect GSTIN edits to be blocked once the vendor has been transacted with — check for existing invoices and advances before planning a correction, and add a new GSTIN instead when the old one is in use
- The PAN of a GST-registered vendor is not editable. Correct the GSTIN and the PAN follows from it
- Treat
isVerified: falseas “saved but unconfirmed”, not as a failure. Note that a successful update replaces the stored verification state, so re-verifying a previously verified identifier with an unreachable service leaves the record unverified - Review changes afterwards through the Vendor Audit Trail API — each update records both the old and the new value
Was this page helpful?