cashod
Geliştiriciler · API v1

Kendi sistemlerinizi Cashod'a bağlayın.

Cashod API'si, kendi sistemlerinizin COD siparişlerini Cashod'a göndermesini, teslimat durumlarını geri okumasını ve ürün kataloğunuzla stoğunuzu senkronize tutmasını sağlar. JSON tabanlı bir HTTP API'sidir — SDK gerekmez.

Temel URLhttps://api.cashod.ma/api/v1
Sipariş oluştur
$ 
Yanıt
Kimlik doğrulama

Tek anahtar, tek mağaza, yalnızca seçtiğiniz kapsamlar.

Cashod'da Ayarlar → Geliştiriciler altında bir anahtar oluşturun. Gizli anahtar yalnızca oluşturulurken bir kez gösterilir ve sonradan kurtarılamaz — kaybolursa anahtarı iptal edip yenisini oluşturun.

Her istekte bearer token olarak gönderin:

Authorization
Authorization: Bearer csk_live_…
Bir anahtar tek bir mağazaya aittir.

Yalnızca o mağazanın verilerini görür ve değiştirir, bu yüzden hiçbir zaman mağaza kimliği göndermezsiniz — anahtar hangi mağazayı kastettiğinizi zaten söyler. Birden fazla mağaza işleten bir satıcı, her mağaza için ayrı bir anahtar oluşturur.

Kapsamlar

Her anahtar ayrıca oluştururken seçtiğiniz kapsamları taşır. Bir yazma kapsamı, karşılık gelen okuma iznini de verir; böylece sipariş oluşturan bir anahtar onları geri okuyabilir. Bir raporlama betiğine salt okunur bir anahtar verin; sızsa bile hiçbir şey oluşturamaz veya iptal edemez.

  • orders:readSiparişleri ve teslimat durumlarını okuma
  • orders:writeSipariş oluşturma — orders:read iznini de verir
  • products:readÜrün kataloğunu okuma
  • products:writeÜrün oluşturma ve güncelleme — products:read iznini de verir
  • stock:writeVaryant stok seviyelerini ayarlama
Hızlı başlangıç

Üç adımda ilk siparişiniz.

  1. 01
    Bir anahtar oluşturun

    Cashod'da Ayarlar → Geliştiriciler'i açın, ihtiyacınız olan kapsamları seçin ve gizli anahtarı kopyalayın — yalnızca bir kez gösterilir.

  2. 02
    Bir sipariş gönderin

    Siparişi kendi external_id değerinizle /v1/orders adresine POST edin; böylece tekrarlanan bir istek asla ikinci bir koliye dönüşmez.

  3. 03
    Teslimatını takip edin

    Kargo firması koliyi ilerlettikçe /v1/orders/{id} üzerinden status, confirmation_status ve tracking_number alanlarını geri okuyun.

POST /v1/orders
curl -X POST https://api.cashod.ma/api/v1/orders \
  -H "Authorization: Bearer csk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "external_id": "order-77",
    "customer": { "name": "Amine Berrada", "phone": "+212600000000" },
    "shipping": { "address": "12 Rue Tarik Ibn Ziad", "city": "Casablanca" },
    "items": [ { "sku": "MON-001-M-NOIR", "quantity": 2 } ]
  }'
Uç noktalar

Bir öğleden sonrada öğrenebileceğiniz küçük bir yüzey.

Her şey https://api.cashod.ma/api/v1 altında.

POST/v1/orders

Ödeme sayfanızdan sipariş oluşturun. external_id ile güvenle yeniden denenebilir.

Kapsamorders:write
GET/v1/orders/{id}

Tek bir siparişi okuyun: kargo durumu, onay durumu ve takip numarası.

Kapsamorders:read
GET/v1/orders

Siparişleri en yeniden başlayarak listeleyin, created_after ile filtreleyin, imleçle sayfalayın.

Kapsamorders:read
POST/v1/products

SKU'ya göre bir ürünü varyantları ve görselleriyle oluşturun veya güncelleyin.

Kapsamproducts:write
PATCH/v1/products/{productId}/variants/{variantId}/stock

Bir varyantın stoğunu mutlak bir seviyeye ayarlayın.

Kapsamstock:write
GET/v1/openapi.json

Referansın üretildiği, makine tarafından okunabilir OpenAPI belgesi.

Yapay zekâ asistanı

Bir yapay zekâ asistanıyla geliştirin

Yapay zekâ kodlama asistanı mı kullanıyorsunuz? Sayfayı elle aktarmak yerine bu istemi kopyalayın. Asla bir anahtar içermez: ürettiği kod sizinkini CASHOD_API_KEY ortam değişkeninden okur.

ChatGPT, Claude, Cursor veya Lovable'a yapıştırın. Bu sayfanın kurallarını ve OpenAPI belgesinin bağlantısını taşır; böylece asistan entegrasyonu sizin altyapınız için yazar.

cashod-api-prompt.md
You are helping me integrate my system (online store, landing page or ERP) with the Cashod API, a cash-on-delivery order platform. Write the integration code following the specification below exactly. Ask me which language/framework I use if you cannot tell from context, and which of the tasks below I need.

The full machine-readable specification is at https://api.cashod.ma/api/v1/openapi.json. Fetch it if you can, and trust it over this summary for field details.

## Rules
- Call the API from my SERVER only, never from browser JavaScript: the key must not reach visitors.
- Read the key from an environment variable named CASHOD_API_KEY (it looks like csk_live_…). Never hard-code it. I create it in Cashod under Settings → Developers; one key belongs to one store.
- Every request: header "Authorization: Bearer <CASHOD_API_KEY>", JSON bodies with "Content-Type: application/json".
- Send only the fields listed here or in the OpenAPI document: unknown fields are rejected with 400 invalid_request.
- Rate limit: 120 requests per minute per key.
- Never let a Cashod failure break my customer's checkout: log it and retry in the background.

## Task 1: send an order
POST https://api.cashod.ma/api/v1/orders  (scope orders:write)
{
  "external_id": "order-77",
  "customer": { "name": "Amine Berrada", "phone": "+212600000000" },
  "shipping": { "address": "12 Rue Tarik Ibn Ziad", "city": "Casablanca" },
  "items": [ { "sku": "MON-001-M-NOIR", "quantity": 2, "unit_price": 149 } ]
}
- Always send external_id, set to my own order id. It makes the call idempotent: a retry returns the existing order (200) instead of creating a second one (201). Without it a retried timeout becomes a second real parcel.
- customer.name, customer.phone, shipping.address, shipping.city are required. shipping.phone is optional (defaults to the customer's).
- items: at least one. Each needs quantity (integer ≥ 1) and one of: sku (variant or product SKU, the usual way), product_id (Cashod product id), or name (free text for an item not in the catalogue; unit_price is then required).
- unit_price: what the customer actually paid per unit. Omit it to use the catalogue price.
- Optional: total (final agreed total; the difference is recorded as a discount), discount, notes, scheduled_for (ISO 8601), source_name (e.g. "Landing page Ramadan"), confirmed (true ONLY if I already confirmed the order with the customer; it skips the confirmation call).

## Task 2: read delivery status
GET https://api.cashod.ma/api/v1/orders/{id}  or  GET https://api.cashod.ma/api/v1/orders?created_after=<ISO 8601>  (scope orders:read)
- An order has status (shipping, e.g. NOT_SHIPPED, SHIPPED, DELIVERED, RETURNED), confirmation_status (e.g. PENDING, CONFIRMED, CANCELLED) and tracking_number once shipped.
- Lists are cursor-paginated, newest first: read data, has_more and next_cursor, and pass ?cursor=<next_cursor> for the next page. limit defaults to 50, max 100.
- Poll at most once a minute.

## Task 3: sync products
POST https://api.cashod.ma/api/v1/products  (scope products:write)
- Keyed on sku: an unknown sku creates the product (201), a known one updates it (200). Safe to send the whole catalogue on a schedule.
- Required: sku, name, category, price, cost_price. Optional: description, sale_price, is_active, track_stock, min_stock, images (URLs), variants.
- variants: each needs sku; optional size, color, price, sale_price, cost_price, stock. Variants are matched by sku; one I do not list is left untouched, never deleted.
- images: omit to keep the existing ones, send a list to replace them, send [] to clear them.
- Setting stock here also needs the stock:write scope.
- 409 conflict: another product already uses this name, or a variant sku belongs to another product. Report it to me; do not retry.

## Task 4: keep stock in sync
PATCH https://api.cashod.ma/api/v1/products/{productId}/variants/{variantId}/stock  (scope stock:write)
{ "stock": 12 }
- Stock is set to an absolute level, never a delta, so a retried call cannot double-apply.

## Errors
Every failure looks like {"error": {"type": "...", "message": "..."}}. Branch on error.type, never on the message text.
- invalid_request (400): fix the payload, do not retry.
- authentication_error (401): missing, unknown or revoked key. Do not retry.
- permission_error (403): the key lacks the scope, or the subscription is not active. Do not retry.
- not_found (404): no such order or product in this key's store.
- rate_limit_exceeded (429) and server_error (500), plus timeouts and network errors: retry with backoff (for example 1 min, 5 min, 30 min). Orders are safe to retry because of external_id.

New optional fields may appear in responses: ignore what you do not recognise.

## When you are done
Show me where the calls happen in my code, the environment variable to set, and a curl command to send one test order.
Rehberler

Alan listesinin size söyleyemedikleri.

Sipariş oluşturma

Her kalemi SKU'suyla tanımlayın — hangisiyle satıyorsanız varyant SKU'su veya ürün SKU'su. unit_price göndermezseniz katalog fiyatı kullanılır; gönderirseniz o geçerli olur — açılış sayfasında bir kampanya varsa istediğiniz de budur.

POST /v1/orders
curl -X POST https://api.cashod.ma/api/v1/orders \
  -H "Authorization: Bearer csk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "external_id": "order-77",
    "customer": { "name": "Amine Berrada", "phone": "+212600000000" },
    "shipping": { "address": "12 Rue Tarik Ibn Ziad", "city": "Casablanca" },
    "items": [ { "sku": "MON-001-M-NOIR", "quantity": 2 } ]
  }'

İdempotans — external_id gönderin

Sipariş için kendi kimliğinizi external_id olarak gönderin; çağrı güvenle yeniden denenebilir hale gelir. Aynı external_id tekrar gelirse Cashod ikinci bir sipariş oluşturmak yerine zaten oluşturduğu siparişi döndürür:

  • 201 Created — artık yeni bir sipariş var.
  • 200 OK — bu external_id için zaten bir sipariş vardı; değiştirilmeden döndürülür.

Bu göründüğünden daha önemlidir. Zaman aşımına uğrayan bir istek genellikle yine de işlenmiştir; external_id olmadan yeniden denemeniz gerçek bir kargo firmasına gönderilen ikinci bir gerçek siparişe dönüşür ve müşteri iki koli alır.

Teslimat durumunu okuma

Bir sipariş status (kargo), confirmation_status (onay araması) ve gönderildikten sonra tracking_number taşır.

GET /v1/orders/{id}
curl https://api.cashod.ma/api/v1/orders/ORDER_ID \
  -H "Authorization: Bearer csk_live_…"

Çok sayıda siparişi takip etmek için GET /v1/orders ile listeleyin ve created_after ile filtreleyin. Dakikada birden sık sorgulamayın; durumlar kargo hızında değiştiği için daha sık döngülerin bir faydası yoktur.

Ürün oluşturma ve güncelleme

sku anahtarlı tek bir uç nokta: bilinmeyen bir SKU ürünü oluşturur, bilinen bir SKU günceller. Böylece neyin zaten var olduğunu kontrol etmeden tüm kataloğunuzu düzenli olarak gönderebilirsiniz.

  • 201 Created — bu SKU yeniydi.
  • 200 OK — bu SKU'ya sahip bir ürün vardı ve güncellendi.
POST /v1/products
curl -X POST https://api.cashod.ma/api/v1/products \
  -H "Authorization: Bearer csk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "sku": "MON-001",
    "name": "Montre Or",
    "category": "Accessoires",
    "price": 199,
    "cost_price": 60,
    "images": [ "https://cdn.example/montre.jpg" ],
    "variants": [
      { "sku": "MON-001-M-NOIR", "size": "M", "color": "Noir", "stock": 7 }
    ]
  }'

Varyantlar SKU'ya göre eşleştirilir ve listelemediğiniz bir varyanta dokunulmaz — asla silinmez. Bir varyantın arkasında genellikle sipariş geçmişi vardır; bu yüzden bir varyantı atlayan bir senkronizasyon onu yok etmemelidir. Varyantları Cashod panelinden silin.

Görseller ise tersine çalışır: images alanını göndermezseniz mevcut görsellere dokunulmaz; bir liste gönderirseniz yeni set o olur; temizlemek için [] gönderin.

cost_price zorunludur. Cashod COGS ve kârı bundan hesaplar; bu alan olmadan oluşturulan bir ürün, yer aldığı her siparişte %100 marj raporlar. Güncellemede, ürün için stok satın alındıktan sonra yok sayılır — bu noktada değiştirmek elinizdeki stoğun maliyetini yeniden yazar.

Bu uç nokta üzerinden bir varyantta stock ayarlamak ayrıca stock:write kapsamını gerektirir. Bu kapsam olmadan çağrı, stok dışındaki her şeyi sessizce kaydetmek yerine reddedilir — böylece bir katalog anahtarı katalog anahtarı olarak kalır.

İki çakışmayı ele almaya değer: mağazadaki başka bir ürün zaten o adı kullanıyor (adlar, SKU'lardan bağımsız olarak mağaza başına benzersizdir) ya da varyant SKU'larınızdan biri başka bir ürüne ait. Her ikisi de çakışmayı belirten 409 conflict olarak döner.

Stoğu senkronize tutma

Stok bir fark değeriyle ayarlanmaz, mutlak bir seviyeye ayarlanır. Varyantın sahip olmasını istediğiniz seviyeyi gönderin — böylece yeniden denenen bir çağrı iki kez uygulanamaz; bir -1 ise bunu sessizce yapardı.

PATCH /v1/products/{productId}/variants/{variantId}/stock
curl -X PATCH https://api.cashod.ma/api/v1/products/PRODUCT_ID/variants/VARIANT_ID/stock \
  -H "Authorization: Bearer csk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "stock": 12 }'

Sayfalama

Liste uç noktaları imleçle, en yeniden başlayarak sayfalanır. Bir yanıt data, has_more ve next_cursor taşır. Sonraki sayfa için o imleci ?cursor= olarak geri gönderin. Sayfa boyutu varsayılan olarak 50, en fazla 100'dür.

Sayfa numarası yerine imleç, çünkü siparişler sürekli gelir: ofset kullanıldığında yeni bir sipariş sonraki her sayfayı bir kaydırır, böylece geçmişi gezen bir istemci bazı satırları sessizce kaçırır, bazılarını ise tekrar okur.

Hatalar

Her hata aynı biçimdedir:

application/json
{
  "error": {
    "type": "invalid_request",
    "message": "No product or variant with SKU \"GHOST-1\" in this store."
  }
}

Mantığınızı message metnine değil, type alanına göre kurun — metin iyileştirilebilir, tür değişmez.

400invalid_requestGönderdiğiniz verideki bir sorun. Mesaj hangisi olduğunu belirtir.
401authentication_errorEksik, bilinmeyen veya iptal edilmiş anahtar.
403permission_errorAnahtarda kapsam eksik veya hesabın aboneliği aktif değil.
404not_foundBu anahtarın mağazasında böyle bir sipariş veya ürün yok.
429rate_limit_exceededBekleyin ve yeniden deneyin.
500server_errorBizden kaynaklı. Yeniden denemek güvenlidir; external_id gönderdiyseniz iki kez denemek de güvenlidir.

Hız sınırları

0anahtar başına dakikada istek

Anahtar başına dakikada 120 istek. Sınır IP adresine göre değil anahtara göredir; böylece aynı barındırmadaki başka bir istemci sizin kotanızı harcayamaz.

Sürümleme

Sürüm yolda yer alır: /v1. Bir sürüm içinde yanıtlara yeni isteğe bağlı alanlar eklenebilir; bu yüzden savunmacı şekilde ayrıştırın ve tanımadıklarınızı yok sayın. Mevcut bir entegrasyonu bozacak her şey bunun yerine yeni bir sürüme girer.

API referansı

Her uç nokta, her alan.

Backend'in kendi OpenAPI belgesinden üretilir; böylece her dağıtımda kodla birlikte değişir ve asla eskimez.

openapi.json
Geliştiriciler için Cashod API: sipariş, stok, webhook