Connect your server to Shrutgyan’s print-on-demand service. Quote a job, submit it once, and track its receipt.
Your integration address is supplied privately by Shrutgyan. Every example uses POD_API_URL as a placeholder for that address.
All balances, quotes, and charges are in Indian rupees (INR). Amount fields ending in _minor use paise: 100 paise = ₹1.00.
One order can contain 1–20 different books for one recipient in India. Printing is deducted from your prepaid balance when the whole order is accepted. Shipping charges are confirmed and settled separately with our team before dispatch.
Get access
- Create a Shrutgyan customer account and give our team the registered email address.
- Ask our team to enable POD client access and approve the exact hostnames where you store print-ready PDFs.
- Arrange prepaid credit. Our team adds it manually; your account cannot add its own balance.
- Open My account → Print on demand. Generate a named API key and copy it immediately. Confirm your login password when generating a key.
- Get your integration address privately from our team and save it as
POD_API_URLon your server.
Keys expire after 90 days by default; choose 1–365 days. Up to five keys can be active per account. A full key is shown only once. If you lose it, revoke it and generate another.
Authenticate every request
X-POD-Key: YOUR_SECRET_API_KEY
Accept: application/json
Use HTTPS and call the API from your backend. Store the key in a secret manager or environment variable. Keep it out of frontend JavaScript, mobile app bundles, source control, URLs, screenshots, and application logs.
Do not use WordPress application passwords or the Authorization header for this API. Browser-origin requests and URL query parameters are rejected. Access is limited to your own prepaid account and jobs.
Rotate a key by creating and deploying a replacement, then revoking the old key. Disabling a client account revokes all its keys; re-enabling it requires new keys.
Follow this integration flow
- Read
GET /optionsfor valid print settings and Indian state codes, andGET /accountfor your balance and approved file hostnames. - Send an
itemsarray of book print settings toPOST /quoteto calculate each book and the complete printing total. - Prepare the order with an
itemsarray containing every book and its final PDF URLs, oneshipping_address, a uniqueexternal_reference, andmax_total_minorset to your approved printing total. - Persist a new
Idempotency-Keywith the complete order JSON before submitting it. - Send
POST /jobs. Save the returnedjob_id, which identifies the whole recipient order. All book entries and one combined printing debit are committed together. - Use
GET /jobs/{job_id}to read the order, each book’s production status, and the receipt state.
Quoting does not reserve funds or lock a price. Submission recalculates the price on the server. If the total exceeds your maximum, or your balance is insufficient, no job or debit is created.
API resources
Append these relative paths to the privately supplied POD_API_URL, without a trailing slash.
| Method / path | Result |
|---|---|
GET /account | Your prepaid balance in paise (balance_minor) and approved_file_hosts. The currency is always INR. |
GET /options | Valid print codes, shipping_countries (IN), shipping_states (code-to-name map), and request limits. |
POST /quote | Calculates each book’s price and the combined printing total. Returns an items array with unit_price_minor, total_minor, pages_rounded, and qty per book; top-level printing_total_minor and total_minor are the complete printing charge. Currency is always INR. It does not create an order or deduct money. |
POST /jobs | Creates one recipient order containing 1–20 books and a delivery address; requires JSON and an Idempotency-Key header. |
GET /jobs/{job_id} | Returns the status and receipt details for one of your submitted jobs. |
Print settings for each book
Each object in items requires all eight fields below. Different books can use different print settings and quantities. Codes are strings; pages and qty are JSON integers. Query /options for the current accepted codes.
| Field | Accepted values |
|---|---|
size | 455: 4 x 5.5 in410: 4 x 10 in (Manuscript)457: 4.5 x 7 in5585: 5.5 x 8.5 in66: 6 x 6 in6595: 6.5 x 9.5 in8251175: 8.25 x 11.75 in8511: 8.5 x 11 in99: 9 x 9 in9513: 9.5 x 13 in1111: 11 x 11 in |
paper | ML80: 80 GSM MaplithoML90: 90 GSM MaplithoML100: 100 GSM MaplithoSM100: 100 GSM Matt Art PaperSM130: 130 GSM Matt Art Paper |
print | BW: Black & White4C: 4 Color |
cover_print | 0: Single Side1: Both Side |
cover_lam | Matt: MattGlossy: Glossy |
binding | PUR: PaperbackHC: Hardcover |
pages | Integer 1–5,000. Production rounding is returned as pages_rounded. |
qty | Integer 1–10,000. |
For colour printing (4C), select ML100, SM100, or SM130. The API rejects ML80 and ML90 for colour jobs.
Submit a job
Send Content-Type: application/json and an Idempotency-Key of 16–128 letters, numbers, underscores, or hyphens. A UUID is suitable. The JSON body limit is 64 KiB. Unknown fields are rejected.
Order fields
| Field | Requirement |
|---|---|
external_reference | Required. Your unique order reference, 1–128 letters, numbers, dots, colons, underscores, or hyphens. Unique within your account. |
items | Required. Array of 1–20 book objects. The combined quantity across all books must not exceed 10,000 copies. All books in one order are for the same recipient. |
shipping_address | Required. The recipient’s Indian delivery address, using the fields below. For another recipient, submit a separate order with a new reference and retry identifier. |
max_total_minor | Required. Maximum combined printing charge in paise. For example, 50000 means ₹500.00. Normally copy total_minor from your multi-book quote. If printing costs more than this limit, the entire order is rejected without a charge. Shipping is settled separately. |
dispatch | Optional single-line delivery instructions, at most 1,000 UTF-8 bytes. These apply to the whole order. |
Additional fields inside each book
| Field | Requirement |
|---|---|
title | Required for submission; optional when quoting. Single-line book title, at most 200 UTF-8 bytes. |
line_reference | Optional identifier unique within the order, 1–128 letters, numbers, dots, colons, underscores, or hyphens. Defaults to the book’s position: 1, 2, and so on. |
book_urls | Required for submission. Ordered array of 1–10 final print-ready PDF URLs for this book, each at most 4,096 bytes. HTTPS only, on an approved hostname. Do not send this field when quoting. |
description, instructions | Optional single-line text for this book, at most 2,000 UTF-8 bytes each. Send these only when submitting. |
Delivery address fields
Supply these inside shipping_address. Address and contact fields must be single-line strings; unknown fields are rejected.
| Field | Requirement |
|---|---|
name | Required recipient name, at most 120 UTF-8 bytes. |
company | Optional organisation name, at most 120 UTF-8 bytes. |
address_1 | Required house/building, street and locality, at most 200 UTF-8 bytes. |
address_2 | Optional additional address or landmark, at most 200 UTF-8 bytes. |
city | Required city, at most 100 UTF-8 bytes. |
state | Required state code from GET /options, such as MH for Maharashtra. |
postcode | Required six-digit Indian PIN code as a string. |
country | Required. Always IN. International delivery is not supported. |
phone | Required ten-digit Indian phone number, optionally prefixed with +91. Returned in +91 format. |
Files are kept in the supplied order. The submission API records file references; it does not download, inspect, or prove that a URL contains a valid PDF. Provide file links that remain accessible for at least 48 hours after submission. Use your approved storage directly, without redirectors or URL shorteners.
Each book starts as Paid for printing. Shipping charges are still to be settled separately before dispatch. Clients cannot set the charge, account owner, payment state, printer order ID, or production status.
Request examples
The following shell examples read credentials and the private address from environment variables. Replace the illustrative PDF host with an approved hostname for your account.
Check your balance
curl --fail-with-body --silent --show-error \
-H "X-POD-Key: $POD_API_KEY" \
-H "Accept: application/json" \
"$POD_API_URL/account"
Get a quote
Send each book’s settings and number of copies in items. This request is free and does not deduct your balance. Use the combined top-level total_minor as max_total_minor when submitting the whole order. Shipping is not included.
curl --fail-with-body --silent --show-error \
-H "X-POD-Key: $POD_API_KEY" \
-H "Content-Type: application/json" \
--data '{"items":[
{"line_reference":"book-1","title":"First book",
"size":"5585","paper":"ML80","print":"BW",
"cover_print":"1","cover_lam":"Matt","binding":"PUR",
"pages":120,"qty":1},
{"line_reference":"book-2","title":"Second book",
"size":"5585","paper":"ML80","print":"BW",
"cover_print":"1","cover_lam":"Matt","binding":"PUR",
"pages":200,"qty":2}]}' \
"$POD_API_URL/quote"
Prepare your job JSON
Save the following as job.json. The example maximum is illustrative; use the total from your actual quote.
{
"external_reference": "YOUR-ORDER-0001",
"shipping_address": {
"name": "RECIPIENT NAME",
"address_1": "HOUSE AND STREET",
"address_2": "LOCALITY OR LANDMARK",
"city": "Mumbai",
"state": "MH",
"postcode": "400004",
"country": "IN",
"phone": "+919876543210"
},
"items": [
{
"line_reference": "book-1",
"title": "First book",
"size": "5585", "paper": "ML80", "print": "BW",
"cover_print": "1", "cover_lam": "Matt", "binding": "PUR",
"pages": 120, "qty": 1,
"book_urls": ["https://files.example.com/first-book.pdf"]
},
{
"line_reference": "book-2",
"title": "Second book",
"size": "5585", "paper": "ML80", "print": "BW",
"cover_print": "1", "cover_lam": "Matt", "binding": "PUR",
"pages": 200, "qty": 2,
"book_urls": ["https://files.example.com/second-book.pdf"]
}
],
"max_total_minor": 100000,
"dispatch": "Pack all three copies together for this recipient."
}
Submit once
POD_IDEMPOTENCY_KEY is an environment variable containing a unique submission identifier that you generate and save for this job, such as a UUID. It is sent in the Idempotency-Key header so that a retry after a timeout cannot create a second job or charge. Use a new value for each new job; reuse the same value and unchanged job JSON when retrying that job. It is separate from your secret API key.
curl --fail-with-body --silent --show-error \
--connect-timeout 10 --max-time 60 \
-H "X-POD-Key: $POD_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $POD_IDEMPOTENCY_KEY" \
--data-binary @job.json \
"$POD_API_URL/jobs"
Understand the response
A newly accepted job returns HTTP 201 with replayed: false. If you retry an already accepted submission, the API returns HTTP 200 with replayed: true and the same job ID. This means your earlier submission succeeded; no additional job or charge was created. Both responses contain:
| Field | Meaning |
|---|---|
job_id | Shared identifier for the entire recipient order and all its books. |
items | Each book’s line_number, line_reference, title, qty, charged_minor, and production status. |
shipping_address | The saved delivery address for this order, visible only to your authenticated account and authorised staff. |
external_reference, status | Your reference and the order’s production status, initially Paid. When books have different statuses, the order shows Partially processed; check each item’s status. When every book is Dispatched, the order also shows Dispatched. |
currency, charged_minor, printing_total_minor | INR and the combined printing debit in paise for every book. |
shipping_total_minor, shipping_charge_status | null and to_be_settled_separately. Shipping is not free or included in the prepaid printing deduction; our team settles it separately before dispatch. |
balance_after_minor | Your historical balance immediately after this job. Read /account for the latest balance. |
notification_status | pending, sending, sent, or failed. Sent means the email transport accepted the receipt. |
created_at | UTC timestamp when the job was first accepted. |
replayed | false for a newly accepted job. true when a retry returns the existing job without another charge. |
Retries and errors
Persist both your order reference and idempotency key before the first submission. If a timeout leaves the outcome unknown, retry the same JSON with the same identifiers. A replay does not create a second job or debit. A reference is unique per account even if a different idempotency key is sent.
Reusing either identifier with different job details returns 409 pod_idempotency_conflict. Do not silently change the files, quantity, title, or maximum price on a retry. Contact our team to resolve an accepted job before submitting a replacement.
| HTTP status | Action |
|---|---|
| 400 | Correct invalid JSON, fields, options, file hostnames, or missing identifiers. Errors include a readable message. |
| 401 | Check your X-POD-Key. It may be missing, expired, or revoked. |
| 402 | Insufficient prepaid funds. Arrange credit, then retry the unchanged request. |
| 403 | HTTPS or account access is required. Contact our team if disabled. |
| 404 | Job not found. Check the job ID returned by your submission. |
| 409 | Resolve an identifier conflict, or obtain and approve a new quote if the price exceeds your maximum. |
| 413 / 415 | Reduce the body to 64 KiB, or use application/json. |
| 429 | Wait at least the Retry-After value. Limit: 60 requests per minute per account across all keys, and 300 per minute per source connection address. |
| 503 / timeout | Retry the identical request and identifiers with exponential backoff and jitter. Do not generate a new order reference. |
{"code":"pod_insufficient_balance",
"message":"Insufficient prepaid balance. Ask Shrutgyan to add credit.",
"data":{"status":402}}
Balances and submission receipts
The API uses the current Shrutgyan POD calculator for each book. All books, the recipient address, and one combined printing debit are stored together. If any book is invalid or the balance cannot cover the whole order, no book or debit is created. All keys for your account share one balance.
Shipping charges are confirmed and settled separately with our team before dispatch. The prepaid balance deduction and maximum-charge field cover printing only.
Once accepted, one receipt is sent to the client’s registered account email address. It lists every book, quantities, the combined printing charge, and the balance after submission. The delivery recipient is not automatically emailed. No API key, file URL, phone number, or full street address is included in the receipt. Submission acceptance does not confirm printing or dispatch.
If email fails, the job remains accepted and charged. Check notification_status or your account’s submission list; do not create another job to trigger an email. Our team can retry the receipt. Email delivery and spam filtering depend on your mail provider.
View recent submissions and balance transactions in My account → Print on demand. For cancellation or a billing correction, contact our team with the job ID. Cancellation and production edits do not automatically refund or reprice an accepted API job.
