PadniSi integration API

Create listings for an existing profile from a server application. API base: https://padnisi.com/api/v1.

Keys and authentication

API keys are available only for unlocked company profiles. Ask an administrator to issue a named key, then open the API keys card in UserPanel to reveal and copy it on the dedicated page. Keys are hidden by default; older hash-only keys need an administrator to rotate them before they can be revealed. Store integration credentials in your server's secret store, never in client-side application code, URLs, source repositories or logs.

Authorization: Bearer pds_live_<publicId>.<secret>

Every API operation requires exactly one Authorization header. Website cookies do not authenticate API calls. Keys grant only their selected scopes, never administrator access. Your profile supplies the owner, active culture and saved phone number. Bulk submission requires a valid saved phone.

Rotation immediately invalidates the old secret. Blocking is reversible; revocation is permanent. Expiry, rotation, blocking and account ineligibility cancel unstarted work. A row already inside its credential-locked database transaction may commit before an administrator's change commits. Created rows remain created. Unblocking does not resume cancelled work; another valid key can poll history and resubmit unprocessed rows.

Discover → upload → submit → poll

Method and pathScopeResponse
GET /api/v1/meprofile:readProfile, scopes and effective request limits
GET /api/v1/catalog/categoriescatalog:readActive category hierarchy in profile culture
GET /api/v1/catalog/cities?after=0&limit=100catalog:readUp to 100 cities, nextAfter cursor
GET /api/v1/catalog/listing-optionscatalog:readCurrencies, enums, tier/decay rules and consent notice
POST /api/v1/uploads/imagesimages:write201: uploadId and expiresAt
POST /api/v1/items/bulkitems:create202: importId, state, submittedAt, itemCount, statusUrl
GET /api/v1/imports/{importId}imports:readProgress and ordered row results
API='https://padnisi.com'
# Supply API_KEY from your server secret store; never enable shell tracing.
curl "$API/api/v1/catalog/categories" -H "Authorization: Bearer $API_KEY"
curl "$API/api/v1/catalog/cities?limit=100" -H "Authorization: Bearer $API_KEY"
curl "$API/api/v1/catalog/listing-options" -H "Authorization: Bearer $API_KEY"
curl "$API/api/v1/uploads/images" -H "Authorization: Bearer $API_KEY" -F '[email protected]'
curl "$API/api/v1/items/bulk" -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' -H 'Idempotency-Key: import-2026-001' \
  --data-binary @batch.json
curl "$API/api/v1/imports/IMPORT_ID" -H "Authorization: Bearer $API_KEY"

The following is a template: replace CATEGORY_ID and CITY_ID with discovered integer IDs before sending. Images are optional; add the returned upload GUIDs to imageUploadIds.

{
  "items": [{
    "externalId": "stock-001",
    "title": "Oak dining table",
    "description": "Solid oak table in good condition.",
    "originalPrice": 120.00,
    "currency": "EUR",
    "categoryId": CATEGORY_ID,
    "cityId": CITY_ID,
    "dealType": "sell",
    "delivery": ["personalPickup"],
    "tier": "free",
    "imageUploadIds": []
  }]
}

Listing fields

JSON names and enum values are case-sensitive. Unknown fields, duplicate object properties, null required values and malformed envelopes are rejected. Do not send userId, culture, status, root category, moderation, balance, paidUntil, embeddings, object keys or image URLs. Root category is derived from the selected active leaf.

Progress, partial failure and publication

202 means durably admitted, not already published. Poll the returned statusUrl, respecting Retry-After (initially two seconds). Back off exponentially to 30 seconds while work remains queued or processing.

Import states: queued, processing, completed, completedWithErrors, cancelled. Each row retains its zero-based index and externalId. Row states: pending, processing, created, alreadyExists, failed, cancelled. Successful rows include itemId and actual listingStatus, including locked. Failed rows include code and, for validation, fieldErrors. Valid siblings may succeed.

Publishing and AI moderation follow website rules. Feed visibility is eventual; a created result does not guarantee immediate browse visibility or prevent later moderation. A notification failure cannot undo a committed listing or charge.

Request failures use application/problem+json with status, title, code and traceId: 400 invalid input/profile prerequisites; 401 unusable credentials/account; 403 scope; 404 missing, wrong-host or other-profile resource; 409 idempotency conflict; 413 oversized body; 415 content type; 429 profile/queue capacity; 503 unavailable dependency. For 429/503, respect Retry-After. Do not retry validation failures unchanged.

Idempotency and external IDs

Send a unique Idempotency-Key (1–128 printable ASCII characters) with each batch. Retain the exact serialized UTF-8 bytes: retrying the same key/body returns the same import, while changing any bytes, including whitespace, returns 409.

For at least 30 days, detailed results and admission keys remain available. After that window, use a new admission key. Successful externalId mappings last for the listing/account lifetime, across secret rotation, batch cleanup and listing soft deletion. Same profile/culture/externalId with the same normalized intent returns alreadyExists; changed content returns external_id_conflict. Deleted listings are not recreated. Failed rows may be corrected in a new batch. Image/property order is significant; trimmed form strings and equivalent decimal representations are normalized.

Limits and retention

Batches: 1–100 rows, up to 2097152 UTF-8 bytes. Uploads: one JPEG, PNG or WebP file, up to 10485760 bytes and 40000000 decoded pixels, maximum 16,384 pixels per dimension. Multipart overhead is bounded separately. Signature and decoder validation both apply.

Unpinned uploads expire after 24 hours. Admission pins valid owned uploads until their rows finish, including retries; expiry cannot delete pinned images. Prepared copies are repeatable and staged originals remain until safe cleanup.

Initial per-profile limits: 10 submissions, 30 uploads and 120 reads per minute. Extra keys do not add quota. Pending rows: 1000 per profile and 10000 globally. The app runs up to 2 import workers globally, one item transaction per profile. Requests time out after 60 seconds. Clients are server-to-server; CORS and an interactive browser console are not provided.

Documentation and API run in the existing application and share its availability.