Introduction
Interactive documentation for the versioned Dukanam mobile API.
Use the login helper below to create a Sanctum device token. The token is saved only in this browser and automatically supplied to every authenticated Try It Out request.
Authenticating requests
To authenticate requests, include an Authorization header with the value "Bearer {ACCESS_TOKEN}".
All authenticated endpoints are marked with a requires authentication badge in the documentation below.
Use the API test login above. A successful login automatically copies the returned data.token into every authenticated endpoint and keeps it across page reloads.
Authentication
Create and manage mobile bearer tokens.
POST api/v1/auth/register
Example request:
curl --request POST \
"https://dukanam.com/api/v1/auth/register" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"name\": \"b\",
\"email\": \"[email protected]\",
\"phone\": \"i\",
\"business_name\": \"y\",
\"password\": \"pBNvYg\",
\"device_name\": \"Scribe API Docs\"
}"
const url = new URL(
"https://dukanam.com/api/v1/auth/register"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "b",
"email": "[email protected]",
"phone": "i",
"business_name": "y",
"password": "pBNvYg",
"device_name": "Scribe API Docs"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/auth/register';
$response = $client->post(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'name' => 'b',
'email' => '[email protected]',
'phone' => 'i',
'business_name' => 'y',
'password' => 'pBNvYg',
'device_name' => 'Scribe API Docs',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/auth/login
Example request:
curl --request POST \
"https://dukanam.com/api/v1/auth/login" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"email\": \"[email protected]\",
\"password\": \"|]|{+-\",
\"remember\": false,
\"device_name\": \"Scribe API Docs\"
}"
const url = new URL(
"https://dukanam.com/api/v1/auth/login"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"email": "[email protected]",
"password": "|]|{+-",
"remember": false,
"device_name": "Scribe API Docs"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/auth/login';
$response = $client->post(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'email' => '[email protected]',
'password' => '|]|{+-',
'remember' => false,
'device_name' => 'Scribe API Docs',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Email a password reset link.
Always returns the same response so callers cannot discover registered email addresses.
Example request:
curl --request POST \
"https://dukanam.com/api/v1/auth/forgot-password" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"email\": \"[email protected]\"
}"
const url = new URL(
"https://dukanam.com/api/v1/auth/forgot-password"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"email": "[email protected]"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/auth/forgot-password';
$response = $client->post(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'email' => '[email protected]',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"message": "If an account exists for that email address, a password reset link has been sent."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Reset an account password.
A successful reset revokes every mobile bearer token and sends a security notification.
Example request:
curl --request POST \
"https://dukanam.com/api/v1/auth/reset-password" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"token\": \"reset-token\",
\"email\": \"[email protected]\",
\"password\": \"new-secure-password\",
\"password_confirmation\": \"new-secure-password\"
}"
const url = new URL(
"https://dukanam.com/api/v1/auth/reset-password"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"token": "reset-token",
"email": "[email protected]",
"password": "new-secure-password",
"password_confirmation": "new-secure-password"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/auth/reset-password';
$response = $client->post(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'token' => 'reset-token',
'email' => '[email protected]',
'password' => 'new-secure-password',
'password_confirmation' => 'new-secure-password',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"message": "Password reset successfully. Sign in with your new password."
}
Example response (422):
{
"message": "The given data was invalid.",
"errors": {
"email": [
"This password reset token is invalid."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Return the current user and active workspaces available under each plan and seat assignment.
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/auth/me" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/auth/me"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/auth/me';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
DELETE api/v1/auth/token
requires authentication
Example request:
curl --request DELETE \
"https://dukanam.com/api/v1/auth/token" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/auth/token"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/auth/token';
$response = $client->delete(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
DELETE api/v1/auth/tokens
requires authentication
Example request:
curl --request DELETE \
"https://dukanam.com/api/v1/auth/tokens" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/auth/tokens"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/auth/tokens';
$response = $client->delete(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Businesses
List the active workspaces available under the caller's current plan and seat assignment.
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
logo_url
string|null
Temporary signed object-storage URL when the logo is stored on S3. Refresh the resource after it expires.
GET api/v1/businesses/{business}
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
logo_url
string|null
Temporary signed object-storage URL when the logo is stored on S3. Refresh the resource after it expires.
subscription
object
plan
object
limits
object
items
integer
Maximum catalogue item count; 0 means unlimited.
Update business settings.
requires authentication
The default_locale field may only be changed by workspace owners and admins. Manual-sharing
templates may only be changed by those roles when the paid feature is enabled for the business.
Example request:
curl --request PATCH \
"https://dukanam.com/api/v1/businesses/1/settings" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"name\": \"b\",
\"legal_name\": \"n\",
\"phone\": \"g\",
\"email\": \"[email protected]\",
\"gst_registration_type\": \"unregistered\",
\"gstin\": \"dljnikhwaykcmyu\",
\"address_line_1\": \"w\",
\"address_line_2\": \"p\",
\"city\": \"w\",
\"state_code\": 1,
\"pincode\": \"569775\",
\"default_place_of_supply\": 1,
\"invoice_prefix\": \"HAWIOT\\/26-27\\/\",
\"prices_include_tax\": false,
\"authorized_signatory\": \"g\",
\"bank_details\": \"z\",
\"upi_id\": \"m\",
\"theme\": \"blue\",
\"default_locale\": \"en\",
\"reminder_message_template\": \"i\",
\"reminder_email_subject_template\": \"y\",
\"invoice_share_subject_template\": \"v\",
\"invoice_share_message_template\": \"d\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/settings"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "b",
"legal_name": "n",
"phone": "g",
"email": "[email protected]",
"gst_registration_type": "unregistered",
"gstin": "dljnikhwaykcmyu",
"address_line_1": "w",
"address_line_2": "p",
"city": "w",
"state_code": 1,
"pincode": "569775",
"default_place_of_supply": 1,
"invoice_prefix": "HAWIOT\/26-27\/",
"prices_include_tax": false,
"authorized_signatory": "g",
"bank_details": "z",
"upi_id": "m",
"theme": "blue",
"default_locale": "en",
"reminder_message_template": "i",
"reminder_email_subject_template": "y",
"invoice_share_subject_template": "v",
"invoice_share_message_template": "d"
};
fetch(url, {
method: "PATCH",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/settings';
$response = $client->patch(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'name' => 'b',
'legal_name' => 'n',
'phone' => 'g',
'email' => '[email protected]',
'gst_registration_type' => 'unregistered',
'gstin' => 'dljnikhwaykcmyu',
'address_line_1' => 'w',
'address_line_2' => 'p',
'city' => 'w',
'state_code' => 1,
'pincode' => '569775',
'default_place_of_supply' => 1,
'invoice_prefix' => 'HAWIOT/26-27/',
'prices_include_tax' => false,
'authorized_signatory' => 'g',
'bank_details' => 'z',
'upi_id' => 'm',
'theme' => 'blue',
'default_locale' => 'en',
'reminder_message_template' => 'i',
'reminder_email_subject_template' => 'y',
'invoice_share_subject_template' => 'v',
'invoice_share_message_template' => 'd',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"data": {
"id": 1,
"name": "Anika Stores",
"slug": "anika-stores",
"role": "owner",
"phone": "9876543210",
"email": "[email protected]",
"legal_name": "Anika Stores Private Limited",
"gstin": "27AAPFU0939F1ZV",
"gst_registration_type": "regular",
"currency": "INR",
"timezone": "Asia/Kolkata",
"address": {
"line_1": "12 Market Road",
"line_2": null,
"city": "Pune",
"state_code": "27",
"pincode": "411001"
},
"default_place_of_supply": "27",
"invoice_prefix": "INV",
"prices_include_tax": true,
"upi_id": "anikastores@bank",
"theme": "indigo",
"default_locale": "hi",
"is_active": true,
"manual_sharing": {
"enabled": true,
"reminder_message_template": "Hello {customer_name}, your current balance is {amount_due}.",
"reminder_email_subject_template": "Payment reminder from {business_name}",
"invoice_share_subject_template": "Invoice {invoice_number} from {business_name}",
"invoice_share_message_template": "Hello {customer_name}, invoice {invoice_number} for {invoice_total} is ready."
},
"subscription": {
"status": "active",
"billing_interval": "monthly",
"trial_ends_at": null,
"renews_at": "2026-09-19T00:00:00.000000Z",
"ends_at": null,
"cancelled_at": null,
"plan": {
"id": 2,
"name": "Smart",
"slug": "smart",
"features": [
"inventory",
"pos",
"expenses"
],
"limits": []
}
}
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/v1/businesses/{business}/dashboard
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/dashboard" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/dashboard"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/dashboard';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Business onboarding
Complete the resumable setup required after registering a new business. Until onboarding finishes, clients may resubmit a completed required step to correct saved data without moving the current step backwards.
GET api/v1/businesses/{business}/onboarding
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/onboarding" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/onboarding"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/onboarding';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
PATCH api/v1/businesses/{business}/onboarding/language
requires authentication
Example request:
curl --request PATCH \
"https://dukanam.com/api/v1/businesses/1/onboarding/language" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"locale\": \"hi\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/onboarding/language"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"locale": "hi"
};
fetch(url, {
method: "PATCH",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/onboarding/language';
$response = $client->patch(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'locale' => 'hi',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business}/onboarding/business
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/onboarding/business" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: multipart/form-data" \
--header "Accept: application/json" \
--form "name=Veera Stores"\
--form "store_type=kirana-store"\
--form "supply_type=goods"\
--form "phone=9876543210"\
--form "logo=@/path/to/file" const url = new URL(
"https://dukanam.com/api/v1/businesses/1/onboarding/business"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "multipart/form-data",
"Accept": "application/json",
};
const body = new FormData();
body.append('name', 'Veera Stores');
body.append('store_type', 'kirana-store');
body.append('supply_type', 'goods');
body.append('phone', '9876543210');
body.append('logo', document.querySelector('input[name="logo"]').files[0]);
fetch(url, {
method: "POST",
headers,
body,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/onboarding/business';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'multipart/form-data',
'Accept' => 'application/json',
],
'multipart' => [
[
'name' => 'name',
'contents' => 'Veera Stores'
],
[
'name' => 'store_type',
'contents' => 'kirana-store'
],
[
'name' => 'supply_type',
'contents' => 'goods'
],
[
'name' => 'phone',
'contents' => '9876543210'
],
[
'name' => 'logo',
'contents' => fopen('/path/to/file', 'r')
],
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
logo_url
string|null
Temporary signed object-storage URL when the logo is stored on S3. Refresh the resource after it expires.
PATCH api/v1/businesses/{business}/onboarding/tax
requires authentication
Example request:
curl --request PATCH \
"https://dukanam.com/api/v1/businesses/1/onboarding/tax" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"gst_status\": \"registered\",
\"gst_registration_type\": \"normal\",
\"gstin\": \"29ABCDE1234F1Z5\",
\"legal_name\": \"a\",
\"address_line_1\": \"12 Market Road\",
\"address_line_2\": \"k\",
\"city\": \"Bengaluru\",
\"state_code\": \"29\",
\"pincode\": \"560001\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/onboarding/tax"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"gst_status": "registered",
"gst_registration_type": "normal",
"gstin": "29ABCDE1234F1Z5",
"legal_name": "a",
"address_line_1": "12 Market Road",
"address_line_2": "k",
"city": "Bengaluru",
"state_code": "29",
"pincode": "560001"
};
fetch(url, {
method: "PATCH",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/onboarding/tax';
$response = $client->patch(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'gst_status' => 'registered',
'gst_registration_type' => 'normal',
'gstin' => '29ABCDE1234F1Z5',
'legal_name' => 'a',
'address_line_1' => '12 Market Road',
'address_line_2' => 'k',
'city' => 'Bengaluru',
'state_code' => '29',
'pincode' => '560001',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business}/onboarding/steps/{step}
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/onboarding/steps/architecto" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"skip\": true
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/onboarding/steps/architecto"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"skip": true
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/onboarding/steps/architecto';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'skip' => true,
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business}/onboarding/product-imports
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/onboarding/product-imports" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: multipart/form-data" \
--header "Accept: application/json" \
--form "file=@/path/to/file" const url = new URL(
"https://dukanam.com/api/v1/businesses/1/onboarding/product-imports"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "multipart/form-data",
"Accept": "application/json",
};
const body = new FormData();
body.append('file', document.querySelector('input[name="file"]').files[0]);
fetch(url, {
method: "POST",
headers,
body,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/onboarding/product-imports';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'multipart/form-data',
'Accept' => 'application/json',
],
'multipart' => [
[
'name' => 'file',
'contents' => fopen('/path/to/file', 'r')
],
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Import every validated product row without exceeding the current plan's total item allowance.
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/onboarding/product-imports/1/confirm" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/onboarding/product-imports/1/confirm"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/onboarding/product-imports/1/confirm';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (422):
{
"message": "Your current plan includes up to 5 items. Upgrade to Smart Books to add more.",
"errors": {
"plan": [
"Your current plan includes up to 5 items. Upgrade to Smart Books to add more."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Contacts
GET api/v1/businesses/{business}/contacts
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/contacts" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"type\": \"customer\",
\"search\": \"b\",
\"per_page\": 22
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/contacts"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"type": "customer",
"search": "b",
"per_page": 22
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/contacts';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'type' => 'customer',
'search' => 'b',
'per_page' => 22,
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create a contact and post its opening balance.
requires authentication
Customer openings post to Accounts receivable; supplier openings post to Accounts payable, offset by Owner equity.
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/contacts" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"type\": \"customer\",
\"profile_type\": \"consumer\",
\"name\": \"b\",
\"company_name\": \"n\",
\"contact_person\": \"g\",
\"phone\": \"z\",
\"email\": \"[email protected]\",
\"gst_treatment\": \"unregistered\",
\"gstin\": \"ljnikhwaykcmyuw\",
\"pan\": \"pwlvqwrsit\",
\"address\": \"c\",
\"billing_address_line_1\": \"p\",
\"billing_address_line_2\": \"s\",
\"billing_city\": \"c\",
\"billing_state_code\": 1,
\"billing_pincode\": \"569775\",
\"shipping_same_as_billing\": false,
\"shipping_address_line_1\": \"n\",
\"shipping_address_line_2\": \"g\",
\"shipping_city\": \"z\",
\"shipping_state_code\": 1,
\"shipping_pincode\": \"569775\",
\"opening_balance\": 22,
\"opening_balance_side\": \"receivable\",
\"opening_balance_date\": \"2026-01-15\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/contacts"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"type": "customer",
"profile_type": "consumer",
"name": "b",
"company_name": "n",
"contact_person": "g",
"phone": "z",
"email": "[email protected]",
"gst_treatment": "unregistered",
"gstin": "ljnikhwaykcmyuw",
"pan": "pwlvqwrsit",
"address": "c",
"billing_address_line_1": "p",
"billing_address_line_2": "s",
"billing_city": "c",
"billing_state_code": 1,
"billing_pincode": "569775",
"shipping_same_as_billing": false,
"shipping_address_line_1": "n",
"shipping_address_line_2": "g",
"shipping_city": "z",
"shipping_state_code": 1,
"shipping_pincode": "569775",
"opening_balance": 22,
"opening_balance_side": "receivable",
"opening_balance_date": "2026-01-15"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/contacts';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'type' => 'customer',
'profile_type' => 'consumer',
'name' => 'b',
'company_name' => 'n',
'contact_person' => 'g',
'phone' => 'z',
'email' => '[email protected]',
'gst_treatment' => 'unregistered',
'gstin' => 'ljnikhwaykcmyuw',
'pan' => 'pwlvqwrsit',
'address' => 'c',
'billing_address_line_1' => 'p',
'billing_address_line_2' => 's',
'billing_city' => 'c',
'billing_state_code' => 1,
'billing_pincode' => '569775',
'shipping_same_as_billing' => false,
'shipping_address_line_1' => 'n',
'shipping_address_line_2' => 'g',
'shipping_city' => 'z',
'shipping_state_code' => 1,
'shipping_pincode' => '569775',
'opening_balance' => 22,
'opening_balance_side' => 'receivable',
'opening_balance_date' => '2026-01-15',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/v1/businesses/{business}/contacts/{id}
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/contacts/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/contacts/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/contacts/1';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update a contact and replace its opening-balance journal.
requires authentication
Example request:
curl --request PUT \
"https://dukanam.com/api/v1/businesses/1/contacts/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"type\": \"customer\",
\"profile_type\": \"consumer\",
\"name\": \"b\",
\"company_name\": \"n\",
\"contact_person\": \"g\",
\"phone\": \"z\",
\"email\": \"[email protected]\",
\"gst_treatment\": \"unregistered\",
\"gstin\": \"ljnikhwaykcmyuw\",
\"pan\": \"pwlvqwrsit\",
\"address\": \"c\",
\"billing_address_line_1\": \"p\",
\"billing_address_line_2\": \"s\",
\"billing_city\": \"c\",
\"billing_state_code\": 1,
\"billing_pincode\": \"569775\",
\"shipping_same_as_billing\": false,
\"shipping_address_line_1\": \"n\",
\"shipping_address_line_2\": \"g\",
\"shipping_city\": \"z\",
\"shipping_state_code\": 1,
\"shipping_pincode\": \"569775\",
\"opening_balance\": 22,
\"opening_balance_side\": \"receivable\",
\"opening_balance_date\": \"2026-01-15\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/contacts/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"type": "customer",
"profile_type": "consumer",
"name": "b",
"company_name": "n",
"contact_person": "g",
"phone": "z",
"email": "[email protected]",
"gst_treatment": "unregistered",
"gstin": "ljnikhwaykcmyuw",
"pan": "pwlvqwrsit",
"address": "c",
"billing_address_line_1": "p",
"billing_address_line_2": "s",
"billing_city": "c",
"billing_state_code": 1,
"billing_pincode": "569775",
"shipping_same_as_billing": false,
"shipping_address_line_1": "n",
"shipping_address_line_2": "g",
"shipping_city": "z",
"shipping_state_code": 1,
"shipping_pincode": "569775",
"opening_balance": 22,
"opening_balance_side": "receivable",
"opening_balance_date": "2026-01-15"
};
fetch(url, {
method: "PUT",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/contacts/1';
$response = $client->put(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'type' => 'customer',
'profile_type' => 'consumer',
'name' => 'b',
'company_name' => 'n',
'contact_person' => 'g',
'phone' => 'z',
'email' => '[email protected]',
'gst_treatment' => 'unregistered',
'gstin' => 'ljnikhwaykcmyuw',
'pan' => 'pwlvqwrsit',
'address' => 'c',
'billing_address_line_1' => 'p',
'billing_address_line_2' => 's',
'billing_city' => 'c',
'billing_state_code' => 1,
'billing_pincode' => '569775',
'shipping_same_as_billing' => false,
'shipping_address_line_1' => 'n',
'shipping_address_line_2' => 'g',
'shipping_city' => 'z',
'shipping_state_code' => 1,
'shipping_pincode' => '569775',
'opening_balance' => 22,
'opening_balance_side' => 'receivable',
'opening_balance_date' => '2026-01-15',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
DELETE api/v1/businesses/{business}/contacts/{id}
requires authentication
Example request:
curl --request DELETE \
"https://dukanam.com/api/v1/businesses/1/contacts/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/contacts/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/contacts/1';
$response = $client->delete(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Khata ledger
GET api/v1/businesses/{business}/ledger-entries
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/ledger-entries" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"contact_id\": 16,
\"kind\": \"n\",
\"from\": \"2026-01-15\",
\"to\": \"2026-01-15\",
\"per_page\": 22
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/ledger-entries"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"contact_id": 16,
"kind": "n",
"from": "2026-01-15",
"to": "2026-01-15",
"per_page": 22
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/ledger-entries';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'contact_id' => 16,
'kind' => 'n',
'from' => '2026-01-15',
'to' => '2026-01-15',
'per_page' => 22,
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Post a manual khata adjustment.
requires authentication
The receivable or payable adjustment is offset to Owner equity. Use invoice, purchase, expense, and payment endpoints for operational transactions.
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/ledger-entries" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"contact_id\": 16,
\"kind\": \"customer_credit\",
\"amount\": 22,
\"occurred_on\": \"2026-01-15\",
\"reference\": \"g\",
\"note\": \"z\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/ledger-entries"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"contact_id": 16,
"kind": "customer_credit",
"amount": 22,
"occurred_on": "2026-01-15",
"reference": "g",
"note": "z"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/ledger-entries';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'contact_id' => 16,
'kind' => 'customer_credit',
'amount' => 22,
'occurred_on' => '2026-01-15',
'reference' => 'g',
'note' => 'z',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/v1/businesses/{business}/ledger-entries/{ledgerEntry_id}
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/ledger-entries/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/ledger-entries/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/ledger-entries/1';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Reverse a manual khata adjustment and its journal.
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/ledger-entries/1/reverse" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"reason\": \"b\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/ledger-entries/1/reverse"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"reason": "b"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/ledger-entries/1/reverse';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'reason' => 'b',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Inventory
GET api/v1/businesses/{business}/items
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/items" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"search\": \"b\",
\"low_stock\": false,
\"per_page\": 22
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/items"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"search": "b",
"low_stock": false,
"per_page": 22
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/items';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'search' => 'b',
'low_stock' => false,
'per_page' => 22,
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
photos
object
url
string
Temporary signed object-storage URL when the photo is stored on S3. Refresh the item after it expires.
meta
object
item_allowance
object
used
integer
Number of catalogue items currently stored.
limit
integer|null
Maximum item count; null means unlimited.
remaining
integer|null
Item slots still available; null means unlimited.
can_create
boolean
Whether another item can be created on the current plan.
upgrade_plan
object|null
Recommended plan name and slug when the allowance is limited.
name
string
Recommended upgrade plan display name.
slug
string
Recommended upgrade plan slug for billing selection.
Create an item and post opening inventory.
requires authentication
Tracked opening stock creates a balanced Inventory / Owner equity journal at purchase cost. Stock and reorder quantities accept up to three decimal places.
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/items" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: multipart/form-data" \
--header "Accept: application/json" \
--form "name=b"\
--form "sku=n"\
--form "barcode=g"\
--form "item_type=goods"\
--form "hsn_sac=zmiyvdljnikhwayk"\
--form "unit=cmyuwpwlvqwrsitc"\
--form "uqc=pscqldzsnrwtujwv"\
--form "gst_taxability=taxable"\
--form "sale_price=24"\
--form "purchase_price=9"\
--form "mrp=15"\
--form "tax_rate=21"\
--form "cess_rate=7"\
--form "stock_quantity=8"\
--form "reorder_level=10"\
--form "track_inventory="\
--form "price_includes_tax="\
--form "remove_photos[]=16"\
--form "photos[]=@/path/to/file" const url = new URL(
"https://dukanam.com/api/v1/businesses/1/items"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "multipart/form-data",
"Accept": "application/json",
};
const body = new FormData();
body.append('name', 'b');
body.append('sku', 'n');
body.append('barcode', 'g');
body.append('item_type', 'goods');
body.append('hsn_sac', 'zmiyvdljnikhwayk');
body.append('unit', 'cmyuwpwlvqwrsitc');
body.append('uqc', 'pscqldzsnrwtujwv');
body.append('gst_taxability', 'taxable');
body.append('sale_price', '24');
body.append('purchase_price', '9');
body.append('mrp', '15');
body.append('tax_rate', '21');
body.append('cess_rate', '7');
body.append('stock_quantity', '8');
body.append('reorder_level', '10');
body.append('track_inventory', '');
body.append('price_includes_tax', '');
body.append('remove_photos[]', '16');
body.append('photos[]', document.querySelector('input[name="photos[]"]').files[0]);
fetch(url, {
method: "POST",
headers,
body,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/items';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'multipart/form-data',
'Accept' => 'application/json',
],
'multipart' => [
[
'name' => 'name',
'contents' => 'b'
],
[
'name' => 'sku',
'contents' => 'n'
],
[
'name' => 'barcode',
'contents' => 'g'
],
[
'name' => 'item_type',
'contents' => 'goods'
],
[
'name' => 'hsn_sac',
'contents' => 'zmiyvdljnikhwayk'
],
[
'name' => 'unit',
'contents' => 'cmyuwpwlvqwrsitc'
],
[
'name' => 'uqc',
'contents' => 'pscqldzsnrwtujwv'
],
[
'name' => 'gst_taxability',
'contents' => 'taxable'
],
[
'name' => 'sale_price',
'contents' => '24'
],
[
'name' => 'purchase_price',
'contents' => '9'
],
[
'name' => 'mrp',
'contents' => '15'
],
[
'name' => 'tax_rate',
'contents' => '21'
],
[
'name' => 'cess_rate',
'contents' => '7'
],
[
'name' => 'stock_quantity',
'contents' => '8'
],
[
'name' => 'reorder_level',
'contents' => '10'
],
[
'name' => 'track_inventory',
'contents' => ''
],
[
'name' => 'price_includes_tax',
'contents' => ''
],
[
'name' => 'remove_photos[]',
'contents' => '16'
],
[
'name' => 'photos[]',
'contents' => fopen('/path/to/file', 'r')
],
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (422):
{
"message": "Your current plan includes up to 5 items. Upgrade to Smart Books to add more.",
"errors": {
"plan": [
"Your current plan includes up to 5 items. Upgrade to Smart Books to add more."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/v1/businesses/{business}/items/{id}
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/items/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/items/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/items/1';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
photos
object
url
string
Temporary signed object-storage URL when the photo is stored on S3. Refresh the item after it expires.
Update an item and account for stock corrections.
requires authentication
Quantity increases post inventory-adjustment income; decreases post an operating expense. Stock and reorder quantities accept up to three decimal places.
Example request:
curl --request PUT \
"https://dukanam.com/api/v1/businesses/1/items/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: multipart/form-data" \
--header "Accept: application/json" \
--form "name=b"\
--form "sku=n"\
--form "barcode=g"\
--form "item_type=goods"\
--form "hsn_sac=zmiyvdljnikhwayk"\
--form "unit=cmyuwpwlvqwrsitc"\
--form "uqc=pscqldzsnrwtujwv"\
--form "gst_taxability=taxable"\
--form "sale_price=24"\
--form "purchase_price=9"\
--form "mrp=15"\
--form "tax_rate=21"\
--form "cess_rate=7"\
--form "stock_quantity=8"\
--form "reorder_level=10"\
--form "track_inventory="\
--form "price_includes_tax="\
--form "remove_photos[]=16"\
--form "photos[]=@/path/to/file" const url = new URL(
"https://dukanam.com/api/v1/businesses/1/items/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "multipart/form-data",
"Accept": "application/json",
};
const body = new FormData();
body.append('name', 'b');
body.append('sku', 'n');
body.append('barcode', 'g');
body.append('item_type', 'goods');
body.append('hsn_sac', 'zmiyvdljnikhwayk');
body.append('unit', 'cmyuwpwlvqwrsitc');
body.append('uqc', 'pscqldzsnrwtujwv');
body.append('gst_taxability', 'taxable');
body.append('sale_price', '24');
body.append('purchase_price', '9');
body.append('mrp', '15');
body.append('tax_rate', '21');
body.append('cess_rate', '7');
body.append('stock_quantity', '8');
body.append('reorder_level', '10');
body.append('track_inventory', '');
body.append('price_includes_tax', '');
body.append('remove_photos[]', '16');
body.append('photos[]', document.querySelector('input[name="photos[]"]').files[0]);
fetch(url, {
method: "PUT",
headers,
body,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/items/1';
$response = $client->put(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'multipart/form-data',
'Accept' => 'application/json',
],
'multipart' => [
[
'name' => 'name',
'contents' => 'b'
],
[
'name' => 'sku',
'contents' => 'n'
],
[
'name' => 'barcode',
'contents' => 'g'
],
[
'name' => 'item_type',
'contents' => 'goods'
],
[
'name' => 'hsn_sac',
'contents' => 'zmiyvdljnikhwayk'
],
[
'name' => 'unit',
'contents' => 'cmyuwpwlvqwrsitc'
],
[
'name' => 'uqc',
'contents' => 'pscqldzsnrwtujwv'
],
[
'name' => 'gst_taxability',
'contents' => 'taxable'
],
[
'name' => 'sale_price',
'contents' => '24'
],
[
'name' => 'purchase_price',
'contents' => '9'
],
[
'name' => 'mrp',
'contents' => '15'
],
[
'name' => 'tax_rate',
'contents' => '21'
],
[
'name' => 'cess_rate',
'contents' => '7'
],
[
'name' => 'stock_quantity',
'contents' => '8'
],
[
'name' => 'reorder_level',
'contents' => '10'
],
[
'name' => 'track_inventory',
'contents' => ''
],
[
'name' => 'price_includes_tax',
'contents' => ''
],
[
'name' => 'remove_photos[]',
'contents' => '16'
],
[
'name' => 'photos[]',
'contents' => fopen('/path/to/file', 'r')
],
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
DELETE api/v1/businesses/{business}/items/{id}
requires authentication
Example request:
curl --request DELETE \
"https://dukanam.com/api/v1/businesses/1/items/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/items/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/items/1';
$response = $client->delete(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Sales invoices
GET api/v1/businesses/{business}/invoices
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/invoices" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"status\": \"posted\",
\"contact_id\": 16,
\"from\": \"2026-01-15\",
\"to\": \"2026-01-15\",
\"search\": \"n\",
\"per_page\": 7
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/invoices"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"status": "posted",
"contact_id": 16,
"from": "2026-01-15",
"to": "2026-01-15",
"search": "n",
"per_page": 7
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/invoices';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'status' => 'posted',
'contact_id' => 16,
'from' => '2026-01-15',
'to' => '2026-01-15',
'search' => 'n',
'per_page' => 7,
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create a sales invoice.
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/invoices" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"contact_id\": 16,
\"issue_date\": \"2026-01-15\",
\"due_date\": \"2026-01-15\",
\"notes\": \"n\",
\"place_of_supply_state_code\": \"gz\",
\"reverse_charge\": false,
\"prices_include_tax\": false,
\"channel\": \"backoffice\",
\"idempotency_key\": \"977e5426-8d13-3824-86aa-b092f8ae52c5\",
\"lines\": [
{
\"item_id\": 16,
\"description\": \"Et animi quos velit et fugiat.\",
\"quantity\": 1,
\"unit_price\": 5,
\"tax_rate\": 19,
\"cess_rate\": 17,
\"discount\": 5,
\"price_includes_tax\": false
}
]
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/invoices"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"contact_id": 16,
"issue_date": "2026-01-15",
"due_date": "2026-01-15",
"notes": "n",
"place_of_supply_state_code": "gz",
"reverse_charge": false,
"prices_include_tax": false,
"channel": "backoffice",
"idempotency_key": "977e5426-8d13-3824-86aa-b092f8ae52c5",
"lines": [
{
"item_id": 16,
"description": "Et animi quos velit et fugiat.",
"quantity": 1,
"unit_price": 5,
"tax_rate": 19,
"cess_rate": 17,
"discount": 5,
"price_includes_tax": false
}
]
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/invoices';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'contact_id' => 16,
'issue_date' => '2026-01-15',
'due_date' => '2026-01-15',
'notes' => 'n',
'place_of_supply_state_code' => 'gz',
'reverse_charge' => false,
'prices_include_tax' => false,
'channel' => 'backoffice',
'idempotency_key' => '977e5426-8d13-3824-86aa-b092f8ae52c5',
'lines' => [
['item_id' => 16, 'description' => 'Et animi quos velit et fugiat.', 'quantity' => 1, 'unit_price' => 5, 'tax_rate' => 19, 'cess_rate' => 17, 'discount' => 5, 'price_includes_tax' => false],
],
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
document_kind
string
Tax document type. Enum: invoice, tax_invoice, bill_of_supply.
GET api/v1/businesses/{business}/invoices/{invoice_id}
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/invoices/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/invoices/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/invoices/1';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business}/invoices/{invoice_id}/payments
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/invoices/1/payments" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"amount\": 1,
\"method\": \"cash\",
\"payment_account_id\": 16,
\"paid_on\": \"2026-01-15\",
\"reference\": \"n\",
\"notes\": \"g\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/invoices/1/payments"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"amount": 1,
"method": "cash",
"payment_account_id": 16,
"paid_on": "2026-01-15",
"reference": "n",
"notes": "g"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/invoices/1/payments';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'amount' => 1,
'method' => 'cash',
'payment_account_id' => 16,
'paid_on' => '2026-01-15',
'reference' => 'n',
'notes' => 'g',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Void an unpaid invoice that has no returns.
requires authentication
Invoices with a payment or a sales return must be settled through the corresponding payment or return workflow and cannot be voided.
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/invoices/1/void" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"reason\": \"b\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/invoices/1/void"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"reason": "b"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/invoices/1/void';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'reason' => 'b',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (422):
{
"message": "Only unpaid, active invoices without returns can be voided.",
"errors": {
"invoice": [
"Only unpaid, active invoices without returns can be voided."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Business documents
GET api/v1/businesses/{business}/documents
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/documents" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"type\": \"quote\",
\"status\": \"b\",
\"contact_id\": 16,
\"per_page\": 22
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/documents"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"type": "quote",
"status": "b",
"contact_id": 16,
"per_page": 22
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/documents';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'type' => 'quote',
'status' => 'b',
'contact_id' => 16,
'per_page' => 22,
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business}/documents/{document_type}
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/documents/quote|purchase_order|purchase_invoice|recurring_invoice|sales_return|purchase_return" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"contact_id\": 16,
\"source_invoice_id\": 16,
\"source_document_id\": 16,
\"issue_date\": \"2026-01-15\",
\"due_date\": \"2026-01-15\",
\"frequency\": \"weekly\",
\"next_issue_date\": \"2026-01-15\",
\"end_date\": \"2026-01-15\",
\"notes\": \"n\",
\"external_reference\": \"g\",
\"place_of_supply_state_code\": \"zm\",
\"reverse_charge\": false,
\"prices_include_tax\": false,
\"lines\": [
{
\"item_id\": 16,
\"source_invoice_line_id\": 16,
\"source_document_line_id\": 16,
\"description\": \"Et animi quos velit et fugiat.\",
\"quantity\": 1,
\"unit_price\": 5,
\"tax_rate\": 19,
\"cess_rate\": 17,
\"discount\": 5,
\"price_includes_tax\": false
}
]
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/documents/quote|purchase_order|purchase_invoice|recurring_invoice|sales_return|purchase_return"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"contact_id": 16,
"source_invoice_id": 16,
"source_document_id": 16,
"issue_date": "2026-01-15",
"due_date": "2026-01-15",
"frequency": "weekly",
"next_issue_date": "2026-01-15",
"end_date": "2026-01-15",
"notes": "n",
"external_reference": "g",
"place_of_supply_state_code": "zm",
"reverse_charge": false,
"prices_include_tax": false,
"lines": [
{
"item_id": 16,
"source_invoice_line_id": 16,
"source_document_line_id": 16,
"description": "Et animi quos velit et fugiat.",
"quantity": 1,
"unit_price": 5,
"tax_rate": 19,
"cess_rate": 17,
"discount": 5,
"price_includes_tax": false
}
]
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/documents/quote|purchase_order|purchase_invoice|recurring_invoice|sales_return|purchase_return';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'contact_id' => 16,
'source_invoice_id' => 16,
'source_document_id' => 16,
'issue_date' => '2026-01-15',
'due_date' => '2026-01-15',
'frequency' => 'weekly',
'next_issue_date' => '2026-01-15',
'end_date' => '2026-01-15',
'notes' => 'n',
'external_reference' => 'g',
'place_of_supply_state_code' => 'zm',
'reverse_charge' => false,
'prices_include_tax' => false,
'lines' => [
['item_id' => 16, 'source_invoice_line_id' => 16, 'source_document_line_id' => 16, 'description' => 'Et animi quos velit et fugiat.', 'quantity' => 1, 'unit_price' => 5, 'tax_rate' => 19, 'cess_rate' => 17, 'discount' => 5, 'price_includes_tax' => false],
],
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/v1/businesses/{business}/documents/{document_id}
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/documents/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/documents/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/documents/1';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business}/documents/{document_id}/convert
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/documents/1/convert" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/documents/1/convert"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/documents/1/convert';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Payments
GET api/v1/businesses/{business}/payments
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/payments" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"direction\": \"received\",
\"from\": \"2026-01-15\",
\"to\": \"2026-01-15\",
\"per_page\": 22
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/payments"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"direction": "received",
"from": "2026-01-15",
"to": "2026-01-15",
"per_page": 22
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/payments';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'direction' => 'received',
'from' => '2026-01-15',
'to' => '2026-01-15',
'per_page' => 22,
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business}/payments
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/payments" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"invoice_id\": 16,
\"business_document_id\": 16,
\"amount\": 22,
\"paid_on\": \"2026-01-15\",
\"method\": \"cash\",
\"payment_account_id\": 16,
\"reference\": \"n\",
\"notes\": \"g\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/payments"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"invoice_id": 16,
"business_document_id": 16,
"amount": 22,
"paid_on": "2026-01-15",
"method": "cash",
"payment_account_id": 16,
"reference": "n",
"notes": "g"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/payments';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'invoice_id' => 16,
'business_document_id' => 16,
'amount' => 22,
'paid_on' => '2026-01-15',
'method' => 'cash',
'payment_account_id' => 16,
'reference' => 'n',
'notes' => 'g',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Expenses
Expense records are a core Purchases capability on every plan. Workspace purchase permissions still apply.
List expenses.
requires authentication
Search and filter business expenses. The response includes totals for the current result, the current month, and the retained voided audit trail.
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/expenses?q=internet&category=Utilities&payment_account_id=9&from=2026-08-01&to=2026-08-31&status=active&per_page=20" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/expenses"
);
const params = {
"q": "internet",
"category": "Utilities",
"payment_account_id": "9",
"from": "2026-08-01",
"to": "2026-08-31",
"status": "active",
"per_page": "20",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/expenses';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'q' => 'internet',
'category' => 'Utilities',
'payment_account_id' => '9',
'from' => '2026-08-01',
'to' => '2026-08-31',
'status' => 'active',
'per_page' => '20',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"data": [
{
"id": 41,
"category": "Utilities",
"payee": "City Internet Services",
"amount_paise": 249900,
"occurred_on": "2026-08-12",
"payment_method": "bank",
"payment_account_id": 9,
"payment_account_name": "HDFC Current Account",
"note": "August internet bill for the main shop",
"voided_at": null,
"void_reason": null,
"created_at": "2026-08-12T10:30:00.000000Z"
}
],
"links": {
"first": "https://example.com/api/v1/businesses/1/expenses?page=1",
"last": "https://example.com/api/v1/businesses/1/expenses?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"path": "https://example.com/api/v1/businesses/1/expenses",
"per_page": 20,
"to": 1,
"total": 1
},
"summary": {
"filtered_total_paise": 249900,
"month_total_paise": 384900,
"month_count": 3,
"voided_count": 1
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
summary
object
filtered_total_paise
integer
Total of non-voided expenses matching the current filters.
month_total_paise
integer
Total of all non-voided expenses in the current calendar month.
month_count
integer
Count of all non-voided expenses in the current calendar month.
voided_count
integer
Count of all retained voided expenses.
Post an expense atomically.
requires authentication
The expense, general-ledger journal, cash-drawer movement, and audit record either all commit or all roll back.
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/expenses" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"category\": \"b\",
\"payee\": \"n\",
\"amount\": 7,
\"occurred_on\": \"2026-01-15\",
\"payment_method\": \"cash\",
\"payment_account_id\": 16,
\"note\": \"n\",
\"idempotency_key\": \"6d61f406-f07d-482d-a284-3e06edfd7f55\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/expenses"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"category": "b",
"payee": "n",
"amount": 7,
"occurred_on": "2026-01-15",
"payment_method": "cash",
"payment_account_id": 16,
"note": "n",
"idempotency_key": "6d61f406-f07d-482d-a284-3e06edfd7f55"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/expenses';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'category' => 'b',
'payee' => 'n',
'amount' => 7,
'occurred_on' => '2026-01-15',
'payment_method' => 'cash',
'payment_account_id' => 16,
'note' => 'n',
'idempotency_key' => '6d61f406-f07d-482d-a284-3e06edfd7f55',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/v1/businesses/{business}/expenses/{expense_id}
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/expenses/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/expenses/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/expenses/1';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Void an expense atomically.
requires authentication
The void marker, journal reversal, cash-drawer reversal, and audit record either all commit or all roll back.
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/expenses/1/void" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"reason\": \"b\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/expenses/1/void"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"reason": "b"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/expenses/1/void';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'reason' => 'b',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POS
GET api/v1/businesses/{business}/pos/items
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/pos/items" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"q\": \"b\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/pos/items"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"q": "b"
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/pos/items';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'q' => 'b',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/v1/businesses/{business}/pos/upi
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/pos/upi" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"amount\": 1,
\"payment_account_id\": 16
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/pos/upi"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"amount": 1,
"payment_account_id": 16
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/pos/upi';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'amount' => 1,
'payment_account_id' => 16,
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List held POS carts for the business.
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/pos/carts" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/pos/carts"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/pos/carts';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Hold a POS cart for later checkout.
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/pos/carts" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"name\": \"b\",
\"contact_id\": 16,
\"lines\": [
{
\"item_id\": 16,
\"quantity\": 4326.41688
}
]
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/pos/carts"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "b",
"contact_id": 16,
"lines": [
{
"item_id": 16,
"quantity": 4326.41688
}
]
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/pos/carts';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'name' => 'b',
'contact_id' => 16,
'lines' => [
['item_id' => 16, 'quantity' => 4326.41688],
],
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business}/pos/checkout
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/pos/checkout" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"contact_id\": 16,
\"idempotency_key\": \"a4855dc5-0acb-33c3-b921-f4291f719ca0\",
\"cart_id\": 16,
\"lines\": [
{
\"item_id\": 16,
\"quantity\": 4326.41688,
\"discount\": 77
}
],
\"payments\": [
{
\"method\": \"cash\",
\"payment_account_id\": 16,
\"amount\": 4326.41688
}
]
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/pos/checkout"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"contact_id": 16,
"idempotency_key": "a4855dc5-0acb-33c3-b921-f4291f719ca0",
"cart_id": 16,
"lines": [
{
"item_id": 16,
"quantity": 4326.41688,
"discount": 77
}
],
"payments": [
{
"method": "cash",
"payment_account_id": 16,
"amount": 4326.41688
}
]
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/pos/checkout';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'contact_id' => 16,
'idempotency_key' => 'a4855dc5-0acb-33c3-b921-f4291f719ca0',
'cart_id' => 16,
'lines' => [
['item_id' => 16, 'quantity' => 4326.41688, 'discount' => 77],
],
'payments' => [
['method' => 'cash', 'payment_account_id' => 16, 'amount' => 4326.41688],
],
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Cash register
GET api/v1/businesses/{business}/cash-register
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/cash-register" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"cash_register_id\": 16
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/cash-register"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"cash_register_id": 16
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/cash-register';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'cash_register_id' => 16,
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business}/cash-register/open
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/cash-register/open" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"cash_register_id\": 16,
\"opening_float\": 22
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/cash-register/open"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"cash_register_id": 16,
"opening_float": 22
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/cash-register/open';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'cash_register_id' => 16,
'opening_float' => 22,
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business}/cash-register/movements
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/cash-register/movements" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"type\": \"cash_in\",
\"cash_register_id\": 16,
\"amount\": 22,
\"notes\": \"g\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/cash-register/movements"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"type": "cash_in",
"cash_register_id": 16,
"amount": 22,
"notes": "g"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/cash-register/movements';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'type' => 'cash_in',
'cash_register_id' => 16,
'amount' => 22,
'notes' => 'g',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business}/cash-register/close
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/cash-register/close" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"counted_cash\": 1,
\"cash_register_id\": 16,
\"closing_notes\": \"n\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/cash-register/close"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"counted_cash": 1,
"cash_register_id": 16,
"closing_notes": "n"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/cash-register/close';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'counted_cash' => 1,
'cash_register_id' => 16,
'closing_notes' => 'n',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Reports
GET api/v1/businesses/{business}/reports
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/reports" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"from\": \"2026-01-15\",
\"to\": \"2026-01-15\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/reports"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"from": "2026-01-15",
"to": "2026-01-15"
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/reports';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'from' => '2026-01-15',
'to' => '2026-01-15',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Business compliance guidance
Get the compliance profile, registrations, evidence metadata and assessed obligations.
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/compliance" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/compliance"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/compliance';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"data": {
"business_id": 16,
"state_code": "29",
"profile": {
"constitution": "proprietorship",
"masked_pan": "ABC****34F",
"district": "Bengaluru Urban",
"local_body": "BBMP",
"premises_type": "rented",
"supply_type": "both",
"gst_registration_status": "not_registered",
"previous_year_turnover_paise": 180000000,
"other_pan_turnover_paise": 25000000,
"employee_count": 4,
"contract_worker_count": 0,
"female_employee_count": 2,
"interstate_sales": false,
"ecommerce_sales": true,
"imports": false,
"exports": false,
"manufactures": false,
"food_business": true,
"uses_weighing_scale": true,
"packs_or_imports_goods": false,
"pharmacy": false,
"serves_alcohol": false,
"fire_risk": false,
"pollution_activity": false,
"reminder_days": [
90,
60,
30,
7,
0
],
"assessment_completed_at": "2026-08-20T12:00:00+05:30",
"next_review_at": "2026-11-20T12:00:00+05:30"
},
"categories": [
{
"id": 13,
"slug": "food-service",
"name": "Restaurant, café and food service",
"nic_section": "I"
}
],
"gst_registrations": [],
"obligations": [
{
"id": 81,
"rule_code": "fssai-registration-licence",
"rule_version": 1,
"title": "FSSAI registration or food licence",
"applicability_reason": "Every food business operator must hold the matching registration or licence. Matched using Guidance Shop facts.",
"applicability_level": "required",
"obligation_type": "licence",
"authority_name": "Food Safety and Standards Authority of India",
"source_url": "https://fssai.gov.in/business/registration",
"application_url": "https://foscos.fssai.gov.in/",
"status": "action_required",
"reference_number": null,
"issued_on": null,
"due_on": null,
"expires_on": null,
"notes": null,
"manual_override": false,
"last_assessed_at": "2026-08-20T12:00:00+05:30",
"documents": []
}
],
"guidance_notice": "Guidance is generated from configurable rules and recorded business facts. Review items marked professional review and verify official sources before relying on them.",
"options": {
"constitutions": {
"proprietorship": "Proprietorship",
"partnership": "Partnership firm",
"llp": "Limited Liability Partnership",
"private_limited": "Private limited company",
"public_limited": "Public limited company",
"opc": "One Person Company",
"huf": "Hindu Undivided Family",
"trust_society": "Trust / society",
"cooperative": "Co-operative society",
"government": "Government entity",
"other": "Other"
},
"supply_types": {
"goods": "Goods only",
"services": "Services only",
"both": "Goods and services"
},
"gst_statuses": {
"not_assessed": "Not assessed",
"not_registered": "Not registered",
"pending": "Application pending",
"active": "Registered / active",
"suspended": "Suspended",
"cancelled": "Cancelled / surrendered"
},
"gst_registration_types": {
"normal": "Normal taxpayer",
"composition": "Composition taxpayer",
"casual": "Casual taxable person",
"non_resident": "Non-resident taxable person",
"isd": "Input Service Distributor (ISD)",
"tds": "Tax Deductor (TDS)",
"tcs": "Tax Collector / e-commerce operator (TCS)",
"sez_unit": "SEZ unit",
"sez_developer": "SEZ developer",
"oidar": "OIDAR / online money gaming supplier",
"uin": "Unique Identity Number holder",
"temporary": "Temporary registration"
}
}
},
"meta": {
"available_categories": [
{
"id": 13,
"slug": "food-service",
"name": "Restaurant, café and food service",
"nic_section": "I",
"description": "Restaurants, cafés, caterers, cloud kitchens and mobile food service."
}
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update business facts and immediately run the deterministic compliance assessment.
requires authentication
Example request:
curl --request PUT \
"https://dukanam.com/api/v1/businesses/1/compliance/profile" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"state_code\": \"29\",
\"category_ids\": [
13
],
\"constitution\": \"proprietorship\",
\"pan\": \"ABCDE1234F\",
\"district\": \"Bengaluru Urban\",
\"local_body\": \"BBMP\",
\"premises_type\": \"rented\",
\"supply_type\": \"both\",
\"gst_registration_status\": \"not_registered\",
\"previous_year_turnover\": 1800000,
\"other_pan_turnover\": 250000,
\"employee_count\": 4,
\"contract_worker_count\": 0,
\"female_employee_count\": 2,
\"interstate_sales\": false,
\"ecommerce_sales\": true,
\"imports\": false,
\"exports\": false,
\"manufactures\": false,
\"food_business\": true,
\"uses_weighing_scale\": true,
\"packs_or_imports_goods\": false,
\"pharmacy\": false,
\"serves_alcohol\": false,
\"fire_risk\": false,
\"pollution_activity\": false,
\"reminder_days\": [
90,
60,
30,
7,
0
]
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/compliance/profile"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"state_code": "29",
"category_ids": [
13
],
"constitution": "proprietorship",
"pan": "ABCDE1234F",
"district": "Bengaluru Urban",
"local_body": "BBMP",
"premises_type": "rented",
"supply_type": "both",
"gst_registration_status": "not_registered",
"previous_year_turnover": 1800000,
"other_pan_turnover": 250000,
"employee_count": 4,
"contract_worker_count": 0,
"female_employee_count": 2,
"interstate_sales": false,
"ecommerce_sales": true,
"imports": false,
"exports": false,
"manufactures": false,
"food_business": true,
"uses_weighing_scale": true,
"packs_or_imports_goods": false,
"pharmacy": false,
"serves_alcohol": false,
"fire_risk": false,
"pollution_activity": false,
"reminder_days": [
90,
60,
30,
7,
0
]
};
fetch(url, {
method: "PUT",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/compliance/profile';
$response = $client->put(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'state_code' => '29',
'category_ids' => [13],
'constitution' => 'proprietorship',
'pan' => 'ABCDE1234F',
'district' => 'Bengaluru Urban',
'local_body' => 'BBMP',
'premises_type' => 'rented',
'supply_type' => 'both',
'gst_registration_status' => 'not_registered',
'previous_year_turnover' => 1800000,
'other_pan_turnover' => 250000,
'employee_count' => 4,
'contract_worker_count' => 0,
'female_employee_count' => 2,
'interstate_sales' => false,
'ecommerce_sales' => true,
'imports' => false,
'exports' => false,
'manufactures' => false,
'food_business' => true,
'uses_weighing_scale' => true,
'packs_or_imports_goods' => false,
'pharmacy' => false,
'serves_alcohol' => false,
'fire_risk' => false,
'pollution_activity' => false,
'reminder_days' => [90, 60, 30, 7, 0],
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"data": {
"business_id": 16,
"state_code": "29",
"profile": {
"constitution": "proprietorship",
"masked_pan": "ABC****34F",
"district": "Bengaluru Urban",
"local_body": "BBMP",
"premises_type": "rented",
"supply_type": "both",
"gst_registration_status": "not_registered",
"previous_year_turnover_paise": 180000000,
"other_pan_turnover_paise": 25000000,
"employee_count": 4,
"contract_worker_count": 0,
"female_employee_count": 2,
"interstate_sales": false,
"ecommerce_sales": true,
"imports": false,
"exports": false,
"manufactures": false,
"food_business": true,
"uses_weighing_scale": true,
"packs_or_imports_goods": false,
"pharmacy": false,
"serves_alcohol": false,
"fire_risk": false,
"pollution_activity": false,
"reminder_days": [
90,
60,
30,
7,
0
],
"assessment_completed_at": "2026-08-20T12:00:00+05:30",
"next_review_at": "2026-11-20T12:00:00+05:30"
},
"categories": [
{
"id": 13,
"slug": "food-service",
"name": "Restaurant, café and food service",
"nic_section": "I"
}
],
"gst_registrations": [],
"obligations": [
{
"id": 81,
"rule_code": "fssai-registration-licence",
"rule_version": 1,
"title": "FSSAI registration or food licence",
"applicability_reason": "Every food business operator must hold the matching registration or licence. Matched using Guidance Shop facts.",
"applicability_level": "required",
"obligation_type": "licence",
"authority_name": "Food Safety and Standards Authority of India",
"source_url": "https://fssai.gov.in/business/registration",
"application_url": "https://foscos.fssai.gov.in/",
"status": "action_required",
"reference_number": null,
"issued_on": null,
"due_on": null,
"expires_on": null,
"notes": null,
"manual_override": false,
"last_assessed_at": "2026-08-20T12:00:00+05:30",
"documents": []
}
],
"guidance_notice": "Guidance is generated from configurable rules and recorded business facts. Review items marked professional review and verify official sources before relying on them.",
"options": {
"constitutions": {
"proprietorship": "Proprietorship",
"partnership": "Partnership firm",
"llp": "Limited Liability Partnership",
"private_limited": "Private limited company",
"public_limited": "Public limited company",
"opc": "One Person Company",
"huf": "Hindu Undivided Family",
"trust_society": "Trust / society",
"cooperative": "Co-operative society",
"government": "Government entity",
"other": "Other"
},
"supply_types": {
"goods": "Goods only",
"services": "Services only",
"both": "Goods and services"
},
"gst_statuses": {
"not_assessed": "Not assessed",
"not_registered": "Not registered",
"pending": "Application pending",
"active": "Registered / active",
"suspended": "Suspended",
"cancelled": "Cancelled / surrendered"
},
"gst_registration_types": {
"normal": "Normal taxpayer",
"composition": "Composition taxpayer",
"casual": "Casual taxable person",
"non_resident": "Non-resident taxable person",
"isd": "Input Service Distributor (ISD)",
"tds": "Tax Deductor (TDS)",
"tcs": "Tax Collector / e-commerce operator (TCS)",
"sez_unit": "SEZ unit",
"sez_developer": "SEZ developer",
"oidar": "OIDAR / online money gaming supplier",
"uin": "Unique Identity Number holder",
"temporary": "Temporary registration"
}
}
},
"meta": {
"available_categories": [
{
"id": 13,
"slug": "food-service",
"name": "Restaurant, café and food service",
"nic_section": "I",
"description": "Restaurants, cafés, caterers, cloud kitchens and mobile food service."
}
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Re-run assessment against the latest published rule revisions.
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/compliance/assess" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/compliance/assess"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/compliance/assess';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"data": {
"matched": 8,
"closed": 1
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business_id}/compliance/gst-registrations
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/compliance/gst-registrations" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"registration_type\": \"composition\",
\"registration_status\": \"active\",
\"gstin\": \"29ABCDE1234F1Z5\",
\"uin\": null,
\"state_code\": \"29\",
\"is_primary\": true,
\"valid_from\": \"2026-04-01\",
\"valid_until\": null
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/compliance/gst-registrations"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"registration_type": "composition",
"registration_status": "active",
"gstin": "29ABCDE1234F1Z5",
"uin": null,
"state_code": "29",
"is_primary": true,
"valid_from": "2026-04-01",
"valid_until": null
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/compliance/gst-registrations';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'registration_type' => 'composition',
'registration_status' => 'active',
'gstin' => '29ABCDE1234F1Z5',
'uin' => null,
'state_code' => '29',
'is_primary' => true,
'valid_from' => '2026-04-01',
'valid_until' => null,
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (201):
{
"data": {
"id": 32,
"business_id": 16,
"registration_type": "composition",
"registration_status": "active",
"gstin": "29ABCDE1234F1Z5",
"uin": null,
"state_code": "29",
"is_primary": true,
"valid_from": "2026-04-01T00:00:00.000000Z",
"valid_until": null,
"created_at": "2026-08-20T06:30:00.000000Z",
"updated_at": "2026-08-20T06:30:00.000000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
DELETE api/v1/businesses/{business_id}/compliance/gst-registrations/{gstRegistration_id}
requires authentication
Example request:
curl --request DELETE \
"https://dukanam.com/api/v1/businesses/1/compliance/gst-registrations/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/compliance/gst-registrations/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/compliance/gst-registrations/1';
$response = $client->delete(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (204):
Empty response
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/v1/businesses/{business_id}/compliance/obligations/{complianceObligation_id}
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/compliance/obligations/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/compliance/obligations/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/compliance/obligations/1';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"data": {
"id": 81,
"rule_code": "fssai-registration-licence",
"rule_version": 1,
"title": "FSSAI registration or food licence",
"applicability_reason": "Every food business operator must hold the matching registration or licence. Matched using Guidance Shop facts.",
"applicability_level": "required",
"obligation_type": "licence",
"authority_name": "Food Safety and Standards Authority of India",
"source_url": "https://fssai.gov.in/business/registration",
"application_url": "https://foscos.fssai.gov.in/",
"status": "obtained",
"reference_number": "FSSAI-10010022000123",
"issued_on": "2026-04-01",
"due_on": null,
"expires_on": "2027-03-31",
"notes": "Certificate verified.",
"manual_override": false,
"last_assessed_at": "2026-08-20T12:00:00+05:30",
"documents": [
{
"id": 44,
"original_name": "fssai-certificate.pdf",
"mime_type": "application/pdf",
"size": 102400,
"document_number": "FSSAI-10010022000123",
"issued_on": "2026-04-01",
"expires_on": "2027-03-31",
"is_current": true,
"download_url": "https://billing.example.com/api/v1/businesses/16/compliance/documents/44/download"
}
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
PATCH api/v1/businesses/{business_id}/compliance/obligations/{complianceObligation_id}
requires authentication
Example request:
curl --request PATCH \
"https://dukanam.com/api/v1/businesses/1/compliance/obligations/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"status\": \"obtained\",
\"reference_number\": \"LIC-2026-1001\",
\"issued_on\": \"2026-04-01\",
\"due_on\": null,
\"expires_on\": \"2027-03-31\",
\"notes\": \"Renewal filed by the accountant.\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/compliance/obligations/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"status": "obtained",
"reference_number": "LIC-2026-1001",
"issued_on": "2026-04-01",
"due_on": null,
"expires_on": "2027-03-31",
"notes": "Renewal filed by the accountant."
};
fetch(url, {
method: "PATCH",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/compliance/obligations/1';
$response = $client->patch(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'status' => 'obtained',
'reference_number' => 'LIC-2026-1001',
'issued_on' => '2026-04-01',
'due_on' => null,
'expires_on' => '2027-03-31',
'notes' => 'Renewal filed by the accountant.',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"data": {
"id": 81,
"rule_code": "fssai-registration-licence",
"rule_version": 1,
"title": "FSSAI registration or food licence",
"applicability_reason": "Every food business operator must hold the matching registration or licence. Matched using Guidance Shop facts.",
"applicability_level": "required",
"obligation_type": "licence",
"authority_name": "Food Safety and Standards Authority of India",
"source_url": "https://fssai.gov.in/business/registration",
"application_url": "https://foscos.fssai.gov.in/",
"status": "obtained",
"reference_number": "FSSAI-10010022000123",
"issued_on": "2026-04-01",
"due_on": null,
"expires_on": "2027-03-31",
"notes": "Certificate verified.",
"manual_override": false,
"last_assessed_at": "2026-08-20T12:00:00+05:30",
"documents": [
{
"id": 44,
"original_name": "fssai-certificate.pdf",
"mime_type": "application/pdf",
"size": 102400,
"document_number": "FSSAI-10010022000123",
"issued_on": "2026-04-01",
"expires_on": "2027-03-31",
"is_current": true,
"download_url": "https://billing.example.com/api/v1/businesses/16/compliance/documents/44/download"
}
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business_id}/compliance/obligations/{complianceObligation_id}/documents
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/compliance/obligations/1/documents" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: multipart/form-data" \
--header "Accept: application/json" \
--form "document_number=FSSAI-10010022000123"\
--form "issued_on=2026-04-01"\
--form "expires_on=2027-03-31"\
--form "document=@/path/to/file" const url = new URL(
"https://dukanam.com/api/v1/businesses/1/compliance/obligations/1/documents"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "multipart/form-data",
"Accept": "application/json",
};
const body = new FormData();
body.append('document_number', 'FSSAI-10010022000123');
body.append('issued_on', '2026-04-01');
body.append('expires_on', '2027-03-31');
body.append('document', document.querySelector('input[name="document"]').files[0]);
fetch(url, {
method: "POST",
headers,
body,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/compliance/obligations/1/documents';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'multipart/form-data',
'Accept' => 'application/json',
],
'multipart' => [
[
'name' => 'document_number',
'contents' => 'FSSAI-10010022000123'
],
[
'name' => 'issued_on',
'contents' => '2026-04-01'
],
[
'name' => 'expires_on',
'contents' => '2027-03-31'
],
[
'name' => 'document',
'contents' => fopen('/path/to/file', 'r')
],
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"data": {
"id": 81,
"rule_code": "fssai-registration-licence",
"rule_version": 1,
"title": "FSSAI registration or food licence",
"applicability_reason": "Every food business operator must hold the matching registration or licence. Matched using Guidance Shop facts.",
"applicability_level": "required",
"obligation_type": "licence",
"authority_name": "Food Safety and Standards Authority of India",
"source_url": "https://fssai.gov.in/business/registration",
"application_url": "https://foscos.fssai.gov.in/",
"status": "obtained",
"reference_number": "FSSAI-10010022000123",
"issued_on": "2026-04-01",
"due_on": null,
"expires_on": "2027-03-31",
"notes": "Certificate verified.",
"manual_override": false,
"last_assessed_at": "2026-08-20T12:00:00+05:30",
"documents": [
{
"id": 44,
"original_name": "fssai-certificate.pdf",
"mime_type": "application/pdf",
"size": 102400,
"document_number": "FSSAI-10010022000123",
"issued_on": "2026-04-01",
"expires_on": "2027-03-31",
"is_current": true,
"download_url": "https://billing.example.com/api/v1/businesses/16/compliance/documents/44/download"
}
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/v1/businesses/{business_id}/compliance/documents/{complianceDocument_id}/download
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/compliance/documents/1/download" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/compliance/documents/1/download"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/compliance/documents/1/download';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GST compliance
GET api/v1/businesses/{business}/gst
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/gst" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/gst"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/gst';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/v1/businesses/{business}/gst/gstr1
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/gst/gstr1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/gst/gstr1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/gst/gstr1';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business}/gst/gstr2b
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/gst/gstr2b" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/gst/gstr2b"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/gst/gstr2b';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Billing
List plans and activation availability
requires authentication
Use razorpay_checkout_enabled for paid checkout. paid_plan_activation_enabled refers only to the
support-only manual activation fallback, while each plan's activation_available covers either path.
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/billing" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/billing"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/billing';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
paid_plan_activation_enabled
boolean
Whether customers may self-activate paid plans.
razorpay_checkout_enabled
boolean
Whether Razorpay subscription checkout is configured.
plans
object
activation_available
boolean
Whether this plan may be selected through the API.
monthly_mrp_paise
integer
Regular monthly price before an active offer.
monthly_price_paise
integer
Effective monthly price after any active offer.
yearly_mrp_paise
integer
Regular yearly price before an active offer.
yearly_price_paise
integer
Effective yearly price after any active offer.
offer
object|null
Active offer label, validity, and discount details.
features
string[]
Effective feature list, including the core expenses capability on every plan.
limits
object
items
integer
Maximum catalogue item count; 0 means unlimited.
List subscription payments
requires authentication
Returns successful subscription charges and mandate authorisations for the business owner. Only captured recurring charges expose an invoice download URL.
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/billing/payments?per_page=20" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/billing/payments"
);
const params = {
"per_page": "20",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/billing/payments';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'per_page' => '20',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Download a subscription invoice
requires authentication
Downloads the immutable PDF invoice for a captured recurring subscription charge.
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/billing/payments/1/invoice" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/billing/payments/1/invoice"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/billing/payments/1/invoice';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Change the current plan
requires authentication
Paid plans return HTTP 422 while online paid-plan activation is disabled. The free plan remains selectable. Changing away from a Razorpay-backed plan cancels that provider subscription immediately before the new plan is activated, so mobile clients must confirm an immediate loss of paid access before submitting. If Razorpay cannot confirm cancellation, the endpoint returns HTTP 422 and leaves the current plan unchanged.
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/billing/change" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"plan_id\": \"architecto\",
\"billing_interval\": \"monthly\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/billing/change"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"plan_id": "architecto",
"billing_interval": "monthly"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/billing/change';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'plan_id' => 'architecto',
'billing_interval' => 'monthly',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (422):
{
"message": "Online paid-plan activation is not configured. Contact support to change this plan.",
"errors": {
"plan_id": [
"Online paid-plan activation is not configured. Contact support to change this plan."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Start Razorpay subscription checkout
requires authentication
Creates a price-versioned Razorpay subscription. Mobile clients must pass the returned subscription_id
to Razorpay Standard Checkout and then send the signed result to the confirm endpoint.
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/billing/checkout" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"plan_id\": \"architecto\",
\"billing_interval\": \"monthly\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/billing/checkout"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"plan_id": "architecto",
"billing_interval": "monthly"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/billing/checkout';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'plan_id' => 'architecto',
'billing_interval' => 'monthly',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (201):
{
"data": {
"checkout_id": 1,
"key": "rzp_test_example",
"subscription_id": "sub_example",
"name": "Dukanam",
"description": "Smart Books · Monthly",
"amount_paise": 99900,
"currency": "INR",
"trial_days": 14,
"prefill": {
"name": "Shop Owner",
"email": "[email protected]",
"contact": "9876543210"
}
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Confirm Razorpay subscription authorisation
requires authentication
The server verifies the Razorpay HMAC signature and fetches provider state before granting access. Trial access starts only after successful payment-method authorisation; a plan without a trial waits for Razorpay to report the subscription as active. When the checkout replaces another Razorpay plan, the previous provider subscription is cancelled immediately before the replacement is activated.
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/billing/checkouts/1/confirm" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"razorpay_payment_id\": \"b\",
\"razorpay_subscription_id\": \"n\",
\"razorpay_signature\": \"gzmiyvdljnikhwaykcmyuwpwlvqwrsitcpscqldzsnrwtujwvlxjklqppwqbewtn\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/billing/checkouts/1/confirm"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"razorpay_payment_id": "b",
"razorpay_subscription_id": "n",
"razorpay_signature": "gzmiyvdljnikhwaykcmyuwpwlvqwrsitcpscqldzsnrwtujwvlxjklqppwqbewtn"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/billing/checkouts/1/confirm';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'razorpay_payment_id' => 'b',
'razorpay_subscription_id' => 'n',
'razorpay_signature' => 'gzmiyvdljnikhwaykcmyuwpwlvqwrsitcpscqldzsnrwtujwvlxjklqppwqbewtn',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business}/billing/cancel
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/billing/cancel" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/billing/cancel"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/billing/cancel';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Data exports
Export business data
requires authentication
CSV exports are intended for reporting and use dukanam-{type}-YYYY-MM-DD.csv filenames. The legacy
business-backup type returns a dukanam-business-export-v2 owner/admin-only customer-data portability
export named dukanam-business-export-YYYY-MM-DD.json. It includes item photos and compliance evidence
content, but is not a restorable platform backup.
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/exports?type=invoices" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"type\": \"contacts\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/exports"
);
const params = {
"type": "invoices",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"type": "contacts"
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/exports';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'type' => 'invoices',
],
'json' => [
'type' => 'contacts',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Team access
Owners and administrators can manage workspace members. Smart Books supports one accountant seat in addition to the owner. Business supports all documented roles, with five total seats including the owner and pending invitations.
List team members, pending invitations, and the 25 most recent expired invitations.
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/team" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/team"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/team';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"data": {
"members": [
{
"id": 2,
"name": "Priya Rao",
"email": "[email protected]",
"role": "cashier",
"status": "active",
"joined_at": "2026-08-21T12:00:00.000000Z"
}
],
"invitations": [],
"roles": {
"cashier": {
"label": "Cashier",
"description": "POS, sales, and cash register access."
},
"accountant": {
"label": "Accountant",
"description": "Sales, purchases, inventory, accounting, reports, compliance, and exports."
}
},
"seats": {
"used": 2,
"limit": 5,
"active": 2,
"pending": 0
}
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
seats
object
limit
integer
Total workspace seat limit. A value of 0 means unlimited seats.
Invite a team member.
requires authentication
Pending invitations reserve a seat and expire after seven days.
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/team/invitations" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"email\": \"[email protected]\",
\"role\": \"cashier\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/team/invitations"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"email": "[email protected]",
"role": "cashier"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/team/invitations';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'email' => '[email protected]',
'role' => 'cashier',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (201):
{
"data": {
"id": 12,
"email": "[email protected]",
"role": "cashier",
"status": "pending",
"expires_at": "2026-08-28T12:00:00.000000Z",
"accepted_at": null,
"invited_by": {
"id": 1,
"name": "Workspace Owner"
}
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Resend a pending or expired invitation with a new secure token.
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/team/invitations/1/resend" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/team/invitations/1/resend"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/team/invitations/1/resend';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"data": {
"id": 12,
"email": "[email protected]",
"role": "cashier",
"status": "pending",
"expires_at": "2026-08-28T12:00:00.000000Z",
"accepted_at": null,
"invited_by": {
"id": 1,
"name": "Workspace Owner"
}
}
}
Example response (422):
{
"message": "All 2 workspace seats are already assigned or reserved.",
"errors": {
"email": [
"All 2 workspace seats are already assigned or reserved."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Cancel a pending invitation and release its reserved seat.
requires authentication
Example request:
curl --request DELETE \
"https://dukanam.com/api/v1/businesses/1/team/invitations/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/team/invitations/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/team/invitations/1';
$response = $client->delete(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (204):
Empty response
Example response (403):
{
"message": "Only the owner can manage administrator invitations."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Change a member's role or suspend/reactivate access.
requires authentication
Example request:
curl --request PATCH \
"https://dukanam.com/api/v1/businesses/1/team/members/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"role\": \"manager\",
\"status\": \"active\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/team/members/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"role": "manager",
"status": "active"
};
fetch(url, {
method: "PATCH",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/team/members/1';
$response = $client->patch(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'role' => 'manager',
'status' => 'active',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"data": {
"id": 2,
"name": "Priya Rao",
"email": "[email protected]",
"role": "manager",
"status": "active",
"joined_at": "2026-08-21T12:00:00.000000Z"
}
}
Example response (422):
{
"message": "All 2 workspace seats are already assigned or reserved.",
"errors": {
"role": [
"All 2 workspace seats are already assigned or reserved."
],
"status": [
"All 2 workspace seats are already assigned or reserved."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Remove a member's workspace access without deleting their user account.
requires authentication
Example request:
curl --request DELETE \
"https://dukanam.com/api/v1/businesses/1/team/members/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/team/members/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/team/members/1';
$response = $client->delete(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (204):
Empty response
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Team invitations
Accept a team invitation as an existing user.
requires authentication
Send a valid Sanctum bearer token belonging to the invited email. This endpoint does not create a new token.
Example request:
curl --request POST \
"https://dukanam.com/api/v1/team-invitations/4WvBr4F8Dmcx3FJkL1nEz7PcQs2Yu9Aa/accept" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/team-invitations/4WvBr4F8Dmcx3FJkL1nEz7PcQs2Yu9Aa/accept"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/team-invitations/4WvBr4F8Dmcx3FJkL1nEz7PcQs2Yu9Aa/accept';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"data": {
"user": {
"id": 2,
"name": "Priya Rao",
"email": "[email protected]"
},
"business": {
"id": 1,
"name": "Anika Stores",
"role": "cashier"
}
}
}
Example response (404):
{
"message": "Not Found"
}
Example response (422):
{
"message": "The given data was invalid.",
"errors": {
"email": [
"Sign in with the email address that received this invitation."
],
"invitation": [
"This workspace is no longer available."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Inspect a team invitation.
This endpoint does not require authentication. The opaque token is supplied by the invitation email.
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/team-invitations/4WvBr4F8Dmcx3FJkL1nEz7PcQs2Yu9Aa" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/team-invitations/4WvBr4F8Dmcx3FJkL1nEz7PcQs2Yu9Aa"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/team-invitations/4WvBr4F8Dmcx3FJkL1nEz7PcQs2Yu9Aa';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"data": {
"business": {
"id": 1,
"name": "Anika Stores"
},
"email": "[email protected]",
"role": "cashier",
"role_label": "Cashier",
"status": "pending",
"expires_at": "2026-08-28T12:00:00.000000Z",
"existing_account": false
}
}
Example response (404):
{
"message": "Not Found"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create an account and accept a team invitation.
Use this unauthenticated endpoint only when the invited email does not already belong to a Dukanam user. The response includes a new Sanctum device token.
Example request:
curl --request POST \
"https://dukanam.com/api/v1/team-invitations/4WvBr4F8Dmcx3FJkL1nEz7PcQs2Yu9Aa/register-and-accept" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"name\": \"Priya Rao\",
\"password\": \"secret-pass-123\",
\"device_name\": \"Priya\'s phone\",
\"password_confirmation\": \"secret-pass-123\"
}"
const url = new URL(
"https://dukanam.com/api/v1/team-invitations/4WvBr4F8Dmcx3FJkL1nEz7PcQs2Yu9Aa/register-and-accept"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "Priya Rao",
"password": "secret-pass-123",
"device_name": "Priya's phone",
"password_confirmation": "secret-pass-123"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/team-invitations/4WvBr4F8Dmcx3FJkL1nEz7PcQs2Yu9Aa/register-and-accept';
$response = $client->post(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'name' => 'Priya Rao',
'password' => 'secret-pass-123',
'device_name' => 'Priya\'s phone',
'password_confirmation' => 'secret-pass-123',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"data": {
"user": {
"id": 2,
"name": "Priya Rao",
"email": "[email protected]"
},
"business": {
"id": 1,
"name": "Anika Stores",
"role": "cashier"
},
"token": "1|new-mobile-token"
}
}
Example response (403):
{
"message": "Sign in as the invited user to accept this invitation."
}
Example response (404):
{
"message": "Not Found"
}
Example response (422):
{
"message": "This invitation has expired or is no longer available.",
"errors": {
"invitation": [
"This invitation has expired or is no longer available."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Billing webhooks
Receive Razorpay subscription events
This public provider callback requires a valid X-Razorpay-Signature HMAC header and is idempotent.
Example request:
curl --request POST \
"https://dukanam.com/api/v1/webhooks/razorpay" \
--header "X-Razorpay-Signature: string required Razorpay webhook HMAC signature. Example: 0123456789abcdef" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/webhooks/razorpay"
);
const headers = {
"X-Razorpay-Signature": "string required Razorpay webhook HMAC signature. Example: 0123456789abcdef",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/webhooks/razorpay';
$response = $client->post(
$url,
[
'headers' => [
'X-Razorpay-Signature' => 'string required Razorpay webhook HMAC signature. Example: 0123456789abcdef',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"received": true
}
Example response (401):
{
"message": "Invalid webhook signature."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Lookups
Search tenant-scoped values for lookup controls. Results are limited to the active business and the caller's workspace permissions and plan features.
Search lookup values.
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/lookups?source=customers&q=priya&method=upi&direction=received" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/lookups"
);
const params = {
"source": "customers",
"q": "priya",
"method": "upi",
"direction": "received",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/lookups';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'source' => 'customers',
'q' => 'priya',
'method' => 'upi',
'direction' => 'received',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (200):
{
"data": [
{
"value": "42",
"label": "Priya Sharma",
"meta": "Customer · 9876543210",
"attributes": {
"type": "customer",
"phone": "9876543210"
}
}
],
"meta": {
"source": "customers",
"query": "priya",
"has_more": false
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
value
string
Stable form value for the result.
label
string
Human-readable result label.
meta
string|null
Optional secondary result description.
attributes
object
Source-specific form attributes. Contact results can include type, name, phone, and gstin. Item results include name, price, tax, cess, and stock; purchase_price is present only for callers with purchases, inventory, or accounting permission. Payment-account results include type, methods, default, upi, and open. Outstanding-document results include balance.
meta
object
source
string
Lookup source used for the response.
query
string
Normalized search query.
has_more
boolean
Whether more matching values exist beyond this response.
Payment accounts
GET api/v1/businesses/{business}/payment-accounts
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/payment-accounts" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/payment-accounts"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/payment-accounts';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business}/payment-accounts
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/payment-accounts" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/payment-accounts"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/payment-accounts';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
PATCH api/v1/businesses/{business}/payment-accounts/{paymentAccount_id}
requires authentication
Example request:
curl --request PATCH \
"https://dukanam.com/api/v1/businesses/1/payment-accounts/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/payment-accounts/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "PATCH",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/payment-accounts/1';
$response = $client->patch(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business}/payment-accounts/transfer
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/payment-accounts/transfer" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"from_payment_account_id\": 16,
\"to_payment_account_id\": 16,
\"amount\": 4326.41688,
\"transferred_on\": \"2026-01-15\",
\"reference\": \"m\",
\"notes\": \"i\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/payment-accounts/transfer"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"from_payment_account_id": 16,
"to_payment_account_id": 16,
"amount": 4326.41688,
"transferred_on": "2026-01-15",
"reference": "m",
"notes": "i"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/payment-accounts/transfer';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'from_payment_account_id' => 16,
'to_payment_account_id' => 16,
'amount' => 4326.41688,
'transferred_on' => '2026-01-15',
'reference' => 'm',
'notes' => 'i',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Show eligible transactions and statement-reconciliation history.
requires authentication
Example request:
curl --request GET \
--get "https://dukanam.com/api/v1/businesses/1/payment-accounts/1/reconciliation" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"statement_date\": \"2026-01-15\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/payment-accounts/1/reconciliation"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"statement_date": "2026-01-15"
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/payment-accounts/1/reconciliation';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'statement_date' => '2026-01-15',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
cross-origin-opener-policy: same-origin
x-robots-tag: noindex, nofollow
strict-transport-security: max-age=31536000; includeSubDomains
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Complete and lock a statement reconciliation.
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/payment-accounts/1/reconciliation" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"statement_date\": \"2026-01-15\",
\"statement_balance\": -999999998,
\"transaction_ids\": [
16
],
\"notes\": \"n\"
}"
const url = new URL(
"https://dukanam.com/api/v1/businesses/1/payment-accounts/1/reconciliation"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"statement_date": "2026-01-15",
"statement_balance": -999999998,
"transaction_ids": [
16
],
"notes": "n"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/payment-accounts/1/reconciliation';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'statement_date' => '2026-01-15',
'statement_balance' => -999999998,
'transaction_ids' => [16],
'notes' => 'n',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/businesses/{business}/payment-accounts/{paymentAccount_id}/reconcile/{journalLine_id}
requires authentication
Example request:
curl --request POST \
"https://dukanam.com/api/v1/businesses/1/payment-accounts/1/reconcile/1" \
--header "Authorization: Bearer {ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dukanam.com/api/v1/businesses/1/payment-accounts/1/reconcile/1"
);
const headers = {
"Authorization": "Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://dukanam.com/api/v1/businesses/1/payment-accounts/1/reconcile/1';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {ACCESS_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.