Quick start
1. Create a key. In the app, open a new key on the Admin › Integration › API Keys screen and choose the integration's name and roles. The key is shown only once; only its hash is stored on the server.
2. Send your first request.
curl "https://ozkaymak-erp-dotnet-rvfootuq6a-ew.a.run.app/api/v1/customers?size=2" \
-H "X-Api-Key: ozk_…"
3. The response. Every list comes back in the same envelope:
{
"items": [
{ "id": 482, "name": "…", "type": "customer", "tax_number": "…",
"balance": { "amount": 0.00, "currency": "TRY" }, "active": true }
],
"page": 1, "size": 2, "total": 57
}
All endpoints, fields and examples are in the API reference (OpenAPI 3) — client code can be generated from it.
Authentication
- Send the
X-Api-Keyheader with every request. No key or an unrecognised key returns 401. - A key works with the permissions of the administrator who created it and can't exceed them: the roles chosen are limited to those the administrator can grant; if the administrator is deactivated, the key stops working too.
- A key works only on
/api/v1endpoints; it can't reach the screens' internal endpoints. It sees only your own company's (and your group companies') data. - A key becomes invalid the moment you deactivate it. The screen shows when each key was last used.
Company selection
If your account has several companies, choose the company by company code — the same code as the company value in the screen address:
-H "X-Company: 0002"
- When reading, the selection narrows the result to that company (and its subsidiaries); when writing, it stamps the record with that company.
- In a multi-company account, a write request without a company writes nothing and returns 400. An unknown code returns 400; a company you can't access returns 403.
- In a single-company account the header isn't needed.
Pagination, sorting, search
pagePage number, starting at 11sizePage size; values above 200 are capped at 20050sortSort field (external field name, e.g. name). An unrecognised field returns 400 — it isn't silently ignoreddepends on the resourceorderasc or descascqFree-text search (name, code, tax number …)—Creating and updating records
- Idempotency: add the
Idempotency-Keyheader to thePOSTrequest (at most 80 characters). If you resend with the same key after a timeout, no second record is created; the first result itself is returned. - Update:
PUTchanges the fields you send; it doesn't touch fields you leave out or send asnull. Clearing a field's value isn't supported in this version. - Delete:
DELETEdoesn't delete the record permanently, it deactivates it; the response is 204. Deleting again also returns 204. - Resources open for writing today:
customers,suppliers,business-partners,invoices,employees,sales-orders,webhook-subscriptions,accounting-source-transactions,payroll-change-packages,payroll-results,external-datasets,custom-objects. The rest are read-only.
Money, dates, field names
- Amounts aren't bare numbers; they come back with their currency:
{ "amount": 150000.00, "currency": "TRY" }. - Dates are ISO 8601 (
2026-10-08), timestamps are UTC (2026-10-08T09:46:41Z). - Field names and option values are English and
snake_case:tax_number,"type": "customer".
Errors
Errors follow RFC 7807; type is the class of error and detail is an English explanation. Every response includes a trace_id you can quote in a support ticket.
{
"type": "/errors/Forbidden",
"title": "Forbidden",
"status": 403,
"detail": "The API key's user has no access to company '0002'.",
"trace_id": "0HNP543SOILEB:00000001"
}
errorscode fieldRetry-After header saysRate limits
1,000 requests per minute per company (sliding window). Going over returns 429, and the Retry-After header says how long to wait. For bulk transfers, paginate with size=200.
Versioning
The version is in the address: /api/v1. Within this version no breaking changes are made:
- Adding a field to a response, adding an optional field to a request and adding a new error code happen within the same version — your client should ignore fields it doesn't recognise.
- Removing or renaming a field, changing its type, making an optional field required, or changing the default sort or page size happens only in a new version (
/api/v2). - An old version isn't shut down without its closing date being announced in advance.
Webhooks
Get notified instead of polling for events: invoice issued, order approved, shipment dispatched …
- Subscription:
POST /api/v1/webhook-subscriptions— target address (https), event filter (full name,invoice.*or*). The signing key (whsec_…) is returned only once, at creation and in therotate-secretresponse. - Event catalogue:
GET /api/v1/webhook-events. For testing,POST /{id}/testsends a signedtest.ping; delivery history is atGET /{id}/deliveries. - Delivery: at least once; failed deliveries are retried with backoff, and after repeated failures the subscription is closed automatically. Store the
X-Ozk-Delivery-Idheader so you don't process the same delivery twice. - The target address must be on the public internet; private network, local and cloud metadata addresses aren't connected to, and redirects aren't followed.
Verify the signature — X-Ozk-Signature: t=<unix>,v1=<hex>, v1 = HMAC-SHA256(secret, "<t>.<raw body>"):
import crypto from "node:crypto";
function isValidSignature(header, rawBody, secret) {
const p = Object.fromEntries(header.split(",").map((x) => x.split("=")));
const expected = crypto.createHmac("sha256", secret).update(`${p.t}.${rawBody}`).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(p.t)) < 300; // reject signatures older than 5 minutes
return fresh && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(p.v1));
}
Resources (201)
The discovery endpoint GET /api/v1 gives the list in machine-readable form. Each resource's fields are in the API reference.
customerssuppliersbusiness-partnersinvoicespaymentsemployeesstock-movementssales-ordersequipmentmaintenance-orderscost-centerspurchase-ordersbatchesfixed-assetsbank-accountsaccount-certificationspayment-cardscash-journalsjournal-entry-itemsinternal-orderscontrolling-areasactivity-typesoperating-concernsprofit-centerssettlement-profileschecksbills-of-exchangepos-terminalsaccountsleadsopportunitiesactivitiescontactsreferral-programsreferralsriskscontrolscontrol-testsinternal-auditsrisk-incidentsremediation-actionspoliciesrisk-assessmentssod-rulesinvestment-programsprojectswbs-elementsnetworksnetwork-activitiestime-sheet-entriescondition-recordssupplier-portal-accountssubcontracting-orderssupplier-groupsquota-arrangementspurchase-requisitionsgoods-receiptspurchase-contractspurchase-order-mass-changessupplier-evaluation-runssupplier-evaluation-configscustomer-returnsshipping-pointsreturn-reasonssales-inquiriessales-quotationsconsignment-ordersplantspurchasing-organizationslocationsorder-typesoutput-typesoutput-condition-recordsfleet-kpi-eventsoutput-historyexpense-reportsstorage-locationsstorage-binsmaterial-documentsmaterialsconsignment-stocksreturnable-packagingsphysical-inventory-documentsreservationsstock-transport-orderscycle-countswaveshandling-unitsload-confirmationspowers-of-attorneylegal-noticeslimitation-periodsfee-schedulescontractslearning-programsjob-applicationsjob-classificationsplanner-groupsbills-of-materialprocess-ordershaccp-hazardshaccp-critical-control-pointshaccp-plansmaintenance-plansmaintenance-strategieswork-centerscost-estimatescost-ratesroutingsrepetitive-manufacturing-profilesproduction-versionsengineering-changesmaster-inspection-characteristicsinspection-methodscorrective-actionsquality-action-planssampling-proceduresmanagement-reviewsretention-samplesbreakable-itemsconsumer-complaintssensory-evaluationslabel-verificationsnet-content-checksmaster-data-requestshierarchiesoutbound-deliveriesfreight-ordersfreight-order-stopsvehiclesdrivershubsvehicle-assignmentsvehicle-availabilitiesfuel-logsvehicle-incidentsvehicle-inspectionsgate-eventsdriver-certificatesdriver-licensesdirect-flow-rulescarrier-invoicestransit-laneseta-predictionsgeofencesreturn-deliveriescarrier-allocationscarriersforwarding-ordersfreight-unitsfreight-agreementsmultimodal-routesfreight-tenderscustoms-declarationscharge-typeschemicalssafety-auditswaste-recordssafety-incidentswork-permitsmortgagessd-sales-orderstax-codescondition-typesservice-mastersasset-classesdepreciation-keysdepreciation-areasdivisionspurchasing-groupsdepartmentsledgersunits-of-measurepublic-holidaysemployee-subgroupspersonnel-subareaspos-menu-mappingsprocessesprocess-templatesequipment-bom-itemswebhook-subscriptionswebhook-eventsgl-accountscredit-memosvariance-calculation-linescompaniesbanksuserstasksthird-party-orderspos-checkssegmentsaccounting-source-transactionsaccounting-source-systemsaccounting-rulesaccounting-runspayroll-providerspayroll-change-packagespayroll-resultsexternal-datasetscustom-objects