Bicops Partner APIv1

Interfaccia di integrazione per venditori e partner aziendali.

Panoramica

I dati di prodotti, giacenze e prezzi vengono inviati a Bicops tramite questa API. I dati di ordini e finanza vengono recuperati dalla stessa API. Le richieste massive sono elaborate da una coda; la risposta è 202 con un identificativo batch (batchId).

Versione: /v1. I nomi dei campi non cambiano. I messaggi di risposta sono in inglese; il campo code è stabile.

  • JSON, UTF-8, ISO-8601 (UTC)
  • Ogni risposta include l’header X-Request-Id
  • I record non validi sono rifiutati, quelli validi elaborati
  • Un record inviato con lo stesso sourceId viene aggiornato
GET /v1/me
POST /v1/catalog/products
PATCH /v1/catalog/stock · /v1/catalog/prices
DELETE /v1/catalog/products/{sourceId}
POST /v1/catalog/imports → /{batchId}/complete
GET /v1/catalog/products · /v1/catalog/batches/{id} · /v1/logs/requests

Autenticazione

Ogni richiesta include gli header X-Api-Key e X-Api-Secret. La chiave è emessa da Bicops; il segreto è mostrato solo alla creazione.

L’identità del venditore deriva dalla chiave. Nel corpo non viene inviato alcun identificativo venditore. Una chiave accede solo al proprio account. I permessi sono definiti dagli scope (catalog:read, catalog:write, orders:read).

È possibile impostare una allowlist IP e una data di scadenza. Durante la rotazione due chiavi possono essere attive.

X-Api-Key: 2c1d5c7e-2a1b-4c1e-9d7a-2b6f0e3c9a11
X-Api-Secret: 4Qb…(base64url, 43 chars)
Content-Type: application/json
X-Request-Id: optional-your-correlation-id

Test di connessione: GET /v1/me. La risposta elenca scope e limiti della chiave.

Tipi di chiave

Esistono due tipi di chiave con ambiti diversi. Un servizio chiamato con il tipo sbagliato restituisce 403.

Chiave venditoreCatalogo, ordini, resi, fatture, finanza, report, batch, webhook. Legata a un account venditore.
Chiave aziendaleConti clienti, estratti conto, ricevute di incasso, fatture di vendita, assegnazioni agenti. Legata a una filiale aziendale.
EntrambeGET /v1/me, GET /v1/logs/requests, sottoscrizioni webhook e GET /v1/events.

Primi passi

1. Test di connessione

curl -s https://partner.bicops.tr/v1/me \
  -H "X-Api-Key: 2c1d5c7e-2a1b-4c1e-9d7a-2b6f0e3c9a11" \
  -H "X-Api-Secret: <your-secret>"

2. Invio dei prodotti (fino a 1.000 record). Risposta: 202 e batchId.

curl -s -X POST https://partner.bicops.tr/v1/catalog/products \
  -H "X-Api-Key: <key>" -H "X-Api-Secret: <secret>" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [{
      "sourceId": "SACHS 317 572",
      "name": "AMORTISOR ON AUDI A3 / GOLF V",
      "brand": "SACHS",
      "producerCode": "317 572",
      "oemCodes": ["1T0413031CN", "1T0413031CK"],
      "equivalentCodes": ["FEBI 106124"],
      "price": 3869.60, "currency": "TRY", "pricesIncludeVat": false,
      "stock": 12,
      "warehouses": [{ "code": "ANK", "stock": 8 }, { "code": "IZM", "stock": 4 }],
      "minOrder": 1, "packageAmount": 1, "unit": "AD", "desi": 3.2,
      "images": ["https://cdn.example.com/317572.jpg"],
      "status": 1
    }]
  }'
HTTP/1.1 202 Accepted
X-Request-Id: 7c0e1c5a-…
{
  "batchId": 1042, "status": "queued",
  "received": 1, "accepted": 1, "rejected": 0, "warnings": 0,
  "chunks": 1, "dryRun": false, "issues": [], "requestId": "7c0e1c5a-…"
}

3. Interrogazione del record batch: stato, conteggi, errori di riga.

curl -s https://partner.bicops.tr/v1/catalog/batches/1042 -H "X-Api-Key: <key>" -H "X-Api-Secret: <secret>"
curl -s https://partner.bicops.tr/v1/catalog/batches/1042/errors.csv -H "X-Api-Key: <key>" -H "X-Api-Secret: <secret>" -o errors.csv

4. Aggiornamento di giacenze e prezzi (fino a 5.000 record).

curl -s -X PATCH https://partner.bicops.tr/v1/catalog/stock \
  -H "X-Api-Key: <key>" -H "X-Api-Secret: <secret>" -H "Content-Type: application/json" \
  -d '{"items":[{"sourceId":"SACHS 317 572","stock":9,"warehouses":[{"code":"ANK","stock":5},{"code":"IZM","stock":4}]}]}'

Catalogo

POST /v1/catalog/products inserisce o aggiorna i record tramite sourceId. Vengono elaborati solo i record modificati.

Campi

CampoTipoDescrizione
sourceIdstring (≤200)Obbligatorio. Codice articolo del venditore. Fino a 200 caratteri.
namestring (≤4000)Obbligatorio per i prodotti attivi.
brandstring (≤200)Nome della marca.
producerCode, previousCodestring (≤200)Codice produttore e codice precedente.
oemCodes[]string[] (≤200 items, each ≤100)Codici OEM come array. I codici non vengono concatenati.
equivalentCodes[]string[] (≤200 items)Codici equivalenti ("MARCA CODICE").
price, currency, pricesIncludeVatdecimal · string(3) · booleanPrezzo di listino. TRY, USD o EUR.
stock, warehouses[]decimal · object[] {code: string, stock: decimal}Giacenza totale e ripartizione per magazzino [{code, stock}].
minOrder, packageAmount, boxAmount, unitinteger · integer · integer · string(≤16)Regole d’ordine.
desi, weightdecimal · decimalPeso volumetrico e peso (kg).
images[]string[] (URL, ≤10)URL delle immagini (https).
statusinteger (0 | 1)1 attivo, 0 inattivo.

PATCH /v1/catalog/stock e PATCH /v1/catalog/prices aggiornano solo giacenze e prezzi. Elaborati nella coda prioritaria.

Disattivazione: DELETE /v1/catalog/products/{sourceId} o POST /v1/catalog/products/deactivate.

GET /v1/catalog/products restituisce lo stato dei record lato Bicops.

Importazione da file

Il catalogo completo viene inviato come file NDJSON (un record per riga). gzip è consigliato. Il file viene caricato direttamente nello storage.

  1. POST /v1/catalog/imports: ottenere uploadUrl e batchId
  2. Caricare il file con HTTP PUT su uploadUrl
  3. POST /v1/catalog/imports/{batchId}/complete: avvio dell’elaborazione
  4. GET /v1/catalog/batches/{batchId}: monitoraggio
# 1
curl -s -X POST https://partner.bicops.tr/v1/catalog/imports -H "X-Api-Key: <key>" -H "X-Api-Secret: <secret>" \
  -H "Content-Type: application/json" -d '{"format":"ndjson","gzip":true}'
# → {"batchId":1043,"uploadUrl":"https://files.bicops.tr/partner-raw/…","expiresInSec":900}
# 2
curl -s -X PUT "<uploadUrl>" -H "Content-Type: application/octet-stream" --data-binary @catalog.ndjson.gz
# 3
curl -s -X POST https://partner.bicops.tr/v1/catalog/imports/1043/complete -H "X-Api-Key: <key>" -H "X-Api-Secret: <secret>"

Formato del file

  • Ogni riga è un oggetto JSON autonomo. Tra le righe non ci sono virgole né parentesi quadre.
  • Il file è codificato in UTF-8 e le righe terminano con \n. Le righe vuote vengono ignorate.
  • L’unico campo obbligatorio è sourceId (il vostro codice di magazzino). Un campo non inviato mantiene il valore attuale.
  • Una riga malformata viene rifiutata da sola e il resto del file viene elaborato. I motivi sono in GET /v1/catalog/batches/{id}/errors.
  • Se vengono inviati sia stock sia warehouses, stock deve essere uguale alla somma delle giacenze di magazzino.
  • I prodotti assenti dal file non vengono eliminati. Per disattivarne uno, inviatelo con status: 0.

File di esempio

{"sourceId":"SACHS 317 572","name":"AMORTISOR ON AUDI A3 / GOLF V","brand":"SACHS","producerCode":"317 572","previousCode":"317 571","oemCodes":["1T0413031CN","1T0413031CK"],"equivalentCodes":["FEBI 106124"],"barcodes":["4054228012345"],"price":3869.6,"currency":"TRY","pricesIncludeVat":false,"stock":12,"warehouses":[{"code":"ANK","stock":8},{"code":"IST","stock":4}],"minOrder":1,"packageAmount":1,"boxAmount":2,"unit":"AD","desi":3.2,"weight":1.25,"images":["https://cdn.satici.com/317572.jpg"],"categoryHint":"Amortisor","vehicleHint":"VW Golf V 2003-2008","status":1}
{"sourceId":"MANN W 712/95","name":"YAG FILTRESI","brand":"MANN","oemCodes":["W 712/95","1109AY"],"price":210.5,"currency":"TRY","stock":0,"status":1}
{"sourceId":"BOSCH 0986495255","name":"FREN BALATASI ON","brand":"BOSCH","oemCodes":["0986495255"],"price":1250,"currency":"TRY","stock":6,"warehouses":[{"code":"IZM","stock":6}],"status":1}
{"sourceId":"SACHS 317 571","status":0}

Scarica il file NDJSON di esempio

dryRun=true valida il file senza scrivere. La prima importazione di 1.000.000 di record richiede circa 15 minuti.

Record batch

Ogni richiesta massiva crea un record batch. GET /v1/catalog/batches/{id} restituisce stato, conteggi e durate. /errors restituisce gli errori di riga; /errors.csv lo stesso elenco in CSV.

queuedIn coda
awaiting_uploadIn attesa del caricamento del file
processingIn elaborazione
syncingAggiornamento di catalogo e indice di ricerca
doneCompletato
partialCompletato, alcuni record rifiutati
failedFallito

Conteggi: received, accepted, rejected, changed. Reinviando dati identici, changed = 0.

Endpoint

Tutti gli endpoint sono sotto /v1. Gli endpoint di scrittura richiedono lo scope corrispondente.

Ordini

EndpointDescrizione
GET /ordersElenco ordini (status, updatedSince)
GET /orders/{id}Dettaglio ordine
POST /orders/{id}/approveApprova l’ordine
POST /orders/{id}/statusAggiorna stato {status}
POST /orders/{id}/erp-referenceSalva riferimento ERP {reference}
GET /orders/{id}/messagesMessaggi ordine
GET /orders/{id}/documentsDocumenti ordine

Spedizioni

EndpointDescrizione
POST /orders/{id}/shipmentsRegistra la tua spedizione {trackNumber, cargoId?}
POST /orders/{id}/shipments/createCrea spedizione con corriere Bicops
GET /orders/{id}/shipments/labelEtichetta spedizione (PDF, base64)
GET /orders/carriersElenco corrieri

Resi e annullamenti

EndpointDescrizione
GET /returnsRichieste di reso
GET /returns/{id}Dettaglio reso
POST /returns/{id}/decisionDecisione sul reso {action: approve|reject}
GET /cancellationsOrdini annullati

Fatture

EndpointDescrizione
GET /orders/{id}/invoicesFile fattura allegati all’ordine
POST /orders/{id}/invoiceAllega la tua fattura {fileBase64|fileUrl}
GET /invoicesDocumenti emessi da Bicops a te

Finanza

EndpointDescrizione
GET /finance/settlementsLiquidazione per ordine
GET /finance/statementEstratto mensile
GET /finance/paymentsPagamenti con carta

Webhook ed eventi

EndpointDescrizione
GET /webhooksElenco webhook
POST /webhooksRegistra webhook {url, events[]}
DELETE /webhooks/{id}Disattiva webhook
POST /webhooks/{id}/testInvia evento di test
GET /webhooks/deliveriesRegistro consegne
GET /eventsCoda eventi (cursor)

Report

EndpointDescrizione
GET /reports/salesReport vendite (groupBy=day|month|product|brand)
GET /reports/returnsTasso di reso
GET /reports/catalogStato del catalogo
GET /reports/demandDomanda e prodotti esauriti

Aziendale (chiave filiale)

EndpointDescrizione
GET /customersAnagrafiche clienti
GET /customers/{id}/statementEstratto conto e saldo cliente
GET /accounting/receiptsRicevute di incasso
GET /accounting/invoicesFatture di vendita della filiale
GET /salesmenAssegnazioni agenti

Codici di errore

Risposta di errore: { code, message, details[], requestId }. code è stabile; message è una descrizione in inglese.

{
  "code": "VALIDATION_FAILED",
  "message": "Request body validation failed",
  "details": [{ "field": "items.0.price", "code": "INVALID_FIELD", "message": "price must not be less than 0" }],
  "requestId": "7c0e1c5a-…"
}

Codici di stato HTTP

UNAUTHORIZED (401)Chiave non valida o mancante
FORBIDDEN_SCOPE (403)Scope insufficiente
SELLER_KEY_REQUIRED (403)Il servizio richiede una chiave venditore; è stata usata una chiave aziendale
CORPORATE_KEY_REQUIRED (403)Il servizio richiede una chiave aziendale; è stata usata una chiave venditore
SANDBOX_READ_ONLY (403)Una chiave sandbox non può modificare ordini, resi o fatture; le richieste di catalogo vengono solo validate
IP_NOT_ALLOWED (403)IP non in allowlist
VALIDATION_FAILED (422)Schema del corpo non valido
PAYLOAD_TOO_LARGE (413)Limite di record superato
QUEUE_BUSY (429)Limite di batch in attesa superato; vedere l’header Retry-After
RATE_LIMITED (429)Frequenza delle richieste superata
NOT_FOUND (404)Record non trovato
STORAGE_UNAVAILABLE (503)Storage temporaneamente non disponibile

Codici di record (report errori batch)

SOURCEID_REQUIREDsourceId vuoto
NAME_REQUIREDNome mancante per un prodotto attivo
PRICE_NEGATIVE, STOCK_NEGATIVEValore negativo o non numerico
CURRENCY_INVALIDValuta diversa da TRY, USD o EUR
STATUS_INVALIDstatus diverso da 0 o 1
UNKNOWN_SOURCEIDProdotto non definito
INVALID_JSONRiga non è JSON valido
OEM_TOO_SHORT (avviso)Codice più corto di tre caratteri saltato
WAREHOUSE_STOCK_MISMATCH (avviso)Usato il totale magazzini
DUPLICATE_SOURCEID (avviso)Usato l’ultimo record

Limiti

  • Prodotti: 1.000 record per richiesta. Giacenze e prezzi: 5.000 record per richiesta. Corpo: 6 MB.
  • Frequenza: 600 richieste al minuto per chiave. Oltre: 429.
  • Batch in attesa: 10 per venditore. Oltre: 429.
  • File: nessun limite di record, fino a 2 GB (gzip).
  • L’URL di caricamento è valido 15 minuti.

Registro richieste

GET /v1/logs/requests restituisce le richieste degli ultimi 30 giorni: endpoint, stato, durata, requestId, batchId.

Riferimento