# Keep ## Partner Authorization - [Prerequisites](https://docs.payme.io/keep/partner-authorization/prerequisites): Partner authorization layer protects the Partner's data on the Keep domain against unauthorized access and mutation. # Prerequisites Partner authorization layer protects the Partner's data on the Keep domain against unauthorized access and mutation. The Keep API uses API keys to authenticate requests. Before starting integration you must receive your Partner API keys from your Account Manager: - `Client ID` - `Client Secret` Your API keys carry many privileges, so be sure to keep them **secure**! Do not share your secret API keys in publicly accessible areas such as GitHub, client-side code, and so forth. The API keys must be provided during any interactions via [OAuth2 Access and Refresh Tokens](https://docs.payme.io/keep/partners-api/gettoken) endpoint. All API requests must be made over HTTPS. Calls made over plain HTTP will fail. API requests without authentication will also fail. - [Authorization Flow](https://docs.payme.io/keep/partner-authorization/authorization-flow): Keep uses OAuth 2.0 client credentials. POST /oauth2/token (form-encoded) with grant_type=client_credentials, client_id, client_secret and optional scope (partner-api or seller-api); send Authorization: Bearer ; refresh with grant_type=refresh_token. Use the lifetime returned in expires_in; when supplied, refresh_expires_in gives the refresh-token lifetime. Keep is served on https://.keep.co.il; HTTPS only. Credentials come from your Account Manager and cannot be rotated by you. # Authorization Overview This document provides a high-level overview of the Keep API authentication system. --- ## Introduction The PayMe API uses OAuth 2.0 for secure authentication. API integrators authenticate using the **Client Credentials** flow, which is designed for server-to-server communication where no user interaction is required. --- ## How It Works > **Authentication Flow** > 1. Your server requests an access token using your client credentials > 2. The API returns an access token and refresh token > 3. Use the access token to make authorized API requests > 4. When the access token expires, use the refresh token to obtain a new one > 5. When the refresh token expires, repeat from step 1 --- ## Authentication Methods ### Client Credentials This is the primary authentication method for API integrators. Your server authenticates directly with the PayMe API using a client ID and client secret provided during onboarding. > **When to use:** Server-to-server integrations, backend services, automated processes ### Refresh Token Used to obtain a new access token without re-authenticating with credentials. This ensures continuous API access without storing sensitive credentials for repeated use. > **When to use:** When your current access token has expired or is about to expire --- ## Tokens ### Access Token - Used to authenticate API requests - Short-lived. Use the lifetime returned in `expires_in` - Must be included in the `Authorization` header of every API request - Format: `Bearer ` ### Refresh Token - Used to obtain new access tokens - When supplied, `refresh_expires_in` gives the refresh-token lifetime - Should be stored securely - Cannot be used to make API requests directly --- ## Scopes Scopes define what resources and actions your integration can access. | Scope | Description | |-------|-------------| | `partner-api` | Access to partner-level endpoints and resources | | `seller-api` | Access to seller-level endpoints and resources | Request only the scopes your integration needs to follow the principle of least privilege. --- ## Base URL Keep is served on your partner domain, `https://.keep.co.il`, in both environments; PayMe gives you the domain together with your Keep credentials. Paths start with `/oauth2/token`, `/api/public/...`, `/partner/api/...` and `/seller/api/...`. --- ## Token requests 1. `POST /oauth2/token` with `application/x-www-form-urlencoded` body: `grant_type=client_credentials`, `client_id`, `client_secret`, `scope` — `partner-api` for the Partners API, `seller-api` for the Seller API. The field is optional in the request, but a token issued without a scope is refused with `403` by every Keep endpoint. Endpoint reference: [Obtain access token](https://docs.payme.io/keep/partners-api/gettoken). 2. The response has `access_token`, `refresh_token`, `expires_in`, `token_type`. `refresh_expires_in` is included when supplied. `scope` is included when the issued token has a non-empty scope. 3. Send `Authorization: Bearer ` on every request. 4. Refresh with `grant_type=refresh_token` and the `refresh_token`. A refresh token works once: the response carries a new one, and the new token keeps the scopes of the original. All requests must use HTTPS; plain HTTP and unauthenticated calls fail. --- ## Security Considerations > **Important Security Practices** > - Never expose your client secret in client-side code > - Always use HTTPS for all API communications > - Store tokens securely using encryption > - Implement token refresh before expiration > - Credentials are issued by your Account Manager and cannot be rotated or regenerated by you. If you believe a secret has leaked, contact your Account Manager. --- ## Getting Started 1. **Obtain Credentials** - Contact Keep to receive your `client_id` and `client_secret` 2. **Request Access Token** - Use the Client Credentials flow to obtain tokens 3. **Make API Requests** - Include the access token in your API calls 4. **Handle Token Refresh** - Implement logic to refresh tokens before they expire --- ## Next Steps The token requests are listed in [Token requests](#token-requests); the full request and response formats are on [Obtain access token](https://docs.payme.io/keep/partners-api/gettoken). ## Seller API - [List income documents](https://docs.payme.io/keep/seller-api/listsellerincomedocuments): GET /seller/api/documents/income — List income documents # List income documents - Sandbox: your partner domain on the Keep sandbox: `GET https://.keep.co.il/seller/api/documents/income` - Production: your partner domain: `GET https://.keep.co.il/seller/api/documents/income` ## Credentials - Header `Authorization: Bearer ` Retrieve a list of income documents for the authenticated seller. Documents the seller created in the Keep app are included. ## Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `page` | query | integer | no | Page number. Minimum 0, default 0. | | `limit` | query | integer | no | Items per page. Positive number, at most 500; use a whole-number item count. Default 10. | | `documentTypes` | query | string | no | Filter by document type. Repeat for several types. Allowed values: `invoice`, `receipt`, `invrec`, `deal`, `refund`, `offer`. | | `fromDate` | query | string | no | Filter documents from this date | | `toDate` | query | string | no | Filter documents until this date | | `documentNumber` | query | string | no | Document number, digits | | `clientEmail` | query | string | no | Client email | | `field` | query | string | no | Sort field. Default `docValueDate`. | | `sort` | query | string | no | Sort direction: `asc` or `desc`. Default `desc`. | ## Code samples ### curl ```bash curl -X GET 'https://.keep.co.il/seller/api/documents/income' \ -H 'Authorization: Bearer ' ``` ### Node.js ```javascript const response = await fetch("https://.keep.co.il/seller/api/documents/income", { method: "GET", headers: { "Authorization": "Bearer ", }, }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.get( "https://.keep.co.il/seller/api/documents/income", headers={ "Authorization": "Bearer ", }, ) print(response.text) ``` ### PHP ```php .keep.co.il/seller/api/documents/income'); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ', ], ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 200 — Successful response (success) | Field | Type | Description | | --- | --- | --- | | `payload` | object | | | `payload.page` | integer | | | `payload.limit` | integer | | | `payload.total` | integer | | | `payload.items` | array | | | `payload.items[].id` | string | | | `payload.items[].type` | string | | | `payload.items[].docValueDate` | string | | | `payload.items[].title` | string | | | `payload.items[].docLang` | string | | | `payload.items[].docRegulationId` | string | | | `payload.items[].currency` | string | | | `payload.items[].discount` | number | | | `payload.items[].vatAmount` | number | | | `payload.items[].totalWithVat` | number | | | `payload.items[].url` | string | | ### 400 — Bad Request (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 400, "message": [ "Validation failed" ], "error": "Bad Request" } ``` ### 401 — Unauthorized (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 401, "message": "Unauthorized", "error": "Unauthorized" } ``` - [Seller API](https://docs.payme.io/keep/seller-api): The Seller API lets accounting integrations create and retrieve seller income documents such as invoices and receipts. This page is the editable landing for the Seller API category. # Seller API PayMe Seller API for income document creation using the new invoicing service. ## Overview This API allows sellers to create and manage income documents (invoices, receipts, etc.) using the new invoicing service. ## Document Types | Type | Description | |------|-------------| | `invoice` | Invoice document | | `receipt` | Receipt document | | `invrec` | Invoice + Receipt combined | | `deal` | Deal invoice | | `refund` | Refund/Credit note | | `offer` | Price quote/Offer | ## Supported Currencies Currently only `ILS` (Israeli Shekel) is supported. Amounts are in agorot (1 ILS = 100 agorot). ## Document Languages - `he` - Hebrew - `en` - English - [Create income document](https://docs.payme.io/keep/seller-api/createsellerincomedocument): POST /seller/api/documents/income — Create income document # Create income document - Sandbox: your partner domain on the Keep sandbox: `POST https://.keep.co.il/seller/api/documents/income` - Production: your partner domain: `POST https://.keep.co.il/seller/api/documents/income` ## Credentials - Header `Authorization: Bearer ` Create a new income document (invoice, receipt, deal, etc.) using the new invoicing service. ## More examples Amounts are in agorot (1 ILS = 100 agorot). ### Receipt (cash) ```json { "type": "receipt", "client": { "name": "Example Buyer", "email": "buyer@example.com" }, "currency": "ILS", "docValueDate": "2024-01-15", "docLang": "he", "items": [ { "name": "Product Sale", "quantity": 2, "itemNetPrice": 50000, "itemTotalPrice": 58500, "itemCurrency": "ILS", "isNoItemVat": false } ], "totalAmount": 117000, "totalPaid": 117000, "originTaxDeduction": 0, "cash": { "date": "2024-01-15", "amount": 117000 } } ``` ### Invoice + Receipt (bank transfer) ```json { "type": "invrec", "client": { "name": "Example Buyer", "email": "buyer@example.com", "socialId": "123456782" }, "currency": "ILS", "docValueDate": "2024-01-15", "docLang": "he", "items": [ { "name": "Annual Subscription", "quantity": 1, "itemNetPrice": 240000, "itemTotalPrice": 280800, "itemCurrency": "ILS", "isNoItemVat": false } ], "subTotal": 240000, "totalWithoutVatAmount": 240000, "vatAmount": 40800, "totalAmount": 280800, "totalPaid": 280800, "originTaxDeduction": 0, "bank-transfer": { "date": "2024-01-15", "amount": 280800, "bankNumber": "12", "branchNumber": 456, "accountNumber": 123456 } } ``` ### Receipt with multiple payments ```json { "type": "receipt", "client": { "name": "Example Buyer", "email": "buyer@example.com" }, "currency": "ILS", "docValueDate": "2024-01-15", "docLang": "he", "items": [ { "name": "Professional Services", "quantity": 10, "itemNetPrice": 20000, "itemTotalPrice": 23400, "itemCurrency": "ILS", "isNoItemVat": false } ], "totalAmount": 234000, "totalPaid": 234000, "originTaxDeduction": 0, "cash": { "date": "2024-01-15", "amount": 34000 }, "cc": { "date": "2024-01-15", "amount": 200000, "last4Digits": "5678" } } ``` ### Invoice with payment link ```json { "type": "invoice", "client": { "name": "Example Buyer", "email": "buyer@example.com" }, "currency": "ILS", "docValueDate": "2024-01-15", "dueDate": "2024-01-30", "docLang": "en", "items": [ { "name": "Online Course Subscription", "quantity": 1, "itemNetPrice": 79900, "itemTotalPrice": 93483, "itemCurrency": "ILS", "isNoItemVat": false } ], "subTotal": 79900, "totalWithoutVatAmount": 79900, "vatAmount": 13583, "totalAmount": 93483, "payment": { "isEnabled": true, "clientEmail": "buyer@example.com" } } ``` ### Receipt with cheque ```json { "type": "receipt", "client": { "name": "Example Buyer", "socialId": "123456782" }, "currency": "ILS", "docValueDate": "2024-01-15", "docLang": "he", "items": [ { "name": "Equipment Purchase", "quantity": 1, "itemNetPrice": 1500000, "itemTotalPrice": 1755000, "itemCurrency": "ILS", "isNoItemVat": false } ], "totalAmount": 1755000, "totalPaid": 1755000, "originTaxDeduction": 0, "cheque": { "date": "2024-02-15", "receivedDate": "2024-01-15", "amount": 1755000, "chequeNumber": 1234567, "bankNumber": "10", "branchNumber": 123, "accountNumber": 987654 } } ``` ### VAT-exempt items ```json { "type": "invoice", "client": { "name": "Example Buyer", "socialId": "123456782" }, "currency": "ILS", "docValueDate": "2024-01-15", "dueDate": "2024-02-15", "docLang": "he", "items": [ { "name": "Consulting Services (VAT exempt)", "quantity": 1, "itemNetPrice": 500000, "itemTotalPrice": 500000, "itemCurrency": "ILS", "isNoItemVat": true }, { "name": "Training Materials", "quantity": 1, "itemNetPrice": 100000, "itemTotalPrice": 117000, "itemCurrency": "ILS", "isNoItemVat": false } ], "subTotal": 600000, "totalWithoutVatAmount": 600000, "vatAmount": 17000, "totalAmount": 617000 } ``` ## After the 202 The document is issued asynchronously. The `202` response gives its `id` and `url` at once; the result reaches each URL in `callbacks`. A callback delivery that fails is retried after 60 seconds, three attempts in all. ## Parameters This endpoint takes no path, query or header parameters. ## Request body Content type: `application/json` | Field | Type | Required | Description | | --- | --- | --- | --- | | `type` | string | yes | Document type Allowed values: `invoice`, `receipt`, `invrec`, `deal`, `refund`, `offer`. | | `client` | object | yes | | | `client.name` | string | yes | Client/customer name, at most 255 characters. | | `client.email` | string | no | Client email address | | `client.phone` | string | no | Client phone number | | `client.socialId` | string | no | Client's social/business ID number (ת.ז. / ח.פ.). Exactly 9 digits. Required when the document total is 23,600 ILS or more. | | `currency` | string | yes | Document currency (currently only ILS supported) | | `docValueDate` | string | yes | Document value date | | `dueDate` | string | no | Payment due date (optional). | | `title` | string | no | Document title (optional), at most 255 characters. | | `docLang` | string | yes | Document language Allowed values: `he`, `en`. | | `items` | array | yes | Document line items | | `items[].name` | string | yes | Item name/description, at most 255 characters. | | `items[].quantity` | number | yes | Item quantity, at least 1. | | `items[].itemNetPrice` | number | yes | Item net price (before VAT) | | `items[].itemTotalPrice` | number | no | Item total price (calculated). Required for `invoice`, `invrec`, `deal`, `refund` and `offer`. | | `items[].itemSumNetTotalPrice` | number | no | Item sum net total price (quantity * itemNetPrice) | | `items[].itemCurrency` | string | yes | Item currency | | `items[].isNoItemVat` | boolean | no | VAT exempt flag (true = no VAT for this item). Required for `invoice`, `invrec`, `deal`, `refund` and `offer`. | | `bankDetails` | object | no | Bank account details for payment | | `bankDetails.bankName` | string | no | Bank name | | `bankDetails.branchNumber` | number | no | Branch number | | `bankDetails.accountNumber` | number | no | Account number | | `bankDetails.accountName` | string | no | Account holder name | | `bankDetails.IBAN` | string | no | IBAN number | | `subTotal` | number | no | Subtotal before discount. Required for `invoice`, `invrec`, `deal`, `refund` and `offer`. | | `discount` | number | no | Discount amount | | `totalWithoutVatAmount` | number | no | Total amount without VAT. Required for `invoice`, `invrec`, `deal`, `refund` and `offer`. | | `vatAmount` | number | no | VAT amount. Required for `invoice`, `invrec`, `deal`, `refund` and `offer`. | | `totalAmount` | number | yes | Total amount including VAT | | `totalPaid` | number | no | Total amount paid. Required for `receipt` and `invrec`, and must equal `totalAmount`. | | `originTaxDeduction` | number | no | Tax deduction at source (ניכוי מס במקור). Required for `receipt` and `invrec`; send `0` when there is none. | | `comment` | string | no | Document comments/notes, at most 255 characters. | | `cash` | object | no | Cash payment details | | `cash.date` | string | yes | Payment date | | `cash.amount` | number | yes | Payment amount | | `cc` | object | no | Credit card payment details | | `cc.date` | string | yes | Payment date | | `cc.amount` | number | yes | Payment amount | | `cc.last4Digits` | string | no | Last 4 digits of card | | `bank-transfer` | object | no | Bank transfer payment details | | `bank-transfer.date` | string | yes | Payment date | | `bank-transfer.amount` | number | yes | Payment amount | | `bank-transfer.bankNumber` | string | no | Bank code | | `bank-transfer.branchNumber` | integer | no | Branch number | | `bank-transfer.accountNumber` | integer | yes | Account number | | `cheque` | object | no | Cheque payment details | | `cheque.date` | string | yes | Cheque date | | `cheque.receivedDate` | string | yes | Date cheque was received | | `cheque.amount` | number | yes | Payment amount | | `cheque.chequeNumber` | number | yes | Cheque number | | `cheque.bankNumber` | string | no | Bank code | | `cheque.branchNumber` | integer | no | Branch number | | `cheque.accountNumber` | integer | no | Account number | | `e-wallet` | object | no | E-wallet payment details (PayPal, Bit, etc.) | | `e-wallet.date` | string | yes | Payment date | | `e-wallet.amount` | number | yes | Payment amount | | `e-wallet.appType` | string | yes | Wallet app name | | `e-wallet.nameOfPayingAccount` | string | no | | | `e-wallet.transactionRefNumber` | string | no | | | `e-wallet.additionalDetails` | string | no | At most 255 characters. | | `payment` | object | no | Payment link settings (for invoice/deal) | | `payment.isEnabled` | boolean | yes | Enable payment link | | `payment.clientEmail` | string | no | Email to send payment link to. One of the two is required when `isEnabled` is true. | | `payment.clientPhone` | string | no | Phone to send payment link to. One of the two is required when `isEnabled` is true. | | `callbacks` | object | no | Callback URLs for the asynchronous result. Each must be an `http` or `https` URL on a public host. | | `callbacks.success` | array | no | URLs called when the document is issued. Body: `{ "payload": }`. | | `callbacks.error` | array | no | URLs called when issuing fails. Body: `{ "document": { "id": "" }, "error": }`. A failed document is removed: a later Get income document with that id returns `payload: null`. | ### Request example ```json { "type": "invoice", "client": { "name": "Example Buyer", "email": "buyer@example.com", "phone": "0500000002", "socialId": "123456782" }, "currency": "ILS", "docValueDate": "2024-01-15", "dueDate": "2024-02-15", "docLang": "he", "items": [ { "name": "Consulting Service", "quantity": 1, "itemNetPrice": 100000, "itemTotalPrice": 117000, "itemCurrency": "ILS", "isNoItemVat": false } ], "subTotal": 100000, "totalWithoutVatAmount": 100000, "vatAmount": 17000, "totalAmount": 117000, "comment": "Thank you for your business" } ``` ## Code samples ### curl ```bash curl -X POST 'https://.keep.co.il/seller/api/documents/income' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ' \ --data-raw '{ "type": "invoice", "client": { "name": "Example Buyer", "email": "buyer@example.com", "phone": "0500000002", "socialId": "123456782" }, "currency": "ILS", "docValueDate": "2024-01-15", "dueDate": "2024-02-15", "docLang": "he", "items": [ { "name": "Consulting Service", "quantity": 1, "itemNetPrice": 100000, "itemTotalPrice": 117000, "itemCurrency": "ILS", "isNoItemVat": false } ], "subTotal": 100000, "totalWithoutVatAmount": 100000, "vatAmount": 17000, "totalAmount": 117000, "comment": "Thank you for your business" }' ``` ### Node.js ```javascript const response = await fetch("https://.keep.co.il/seller/api/documents/income", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": "Bearer ", }, body: JSON.stringify({ "type": "invoice", "client": { "name": "Example Buyer", "email": "buyer@example.com", "phone": "0500000002", "socialId": "123456782" }, "currency": "ILS", "docValueDate": "2024-01-15", "dueDate": "2024-02-15", "docLang": "he", "items": [ { "name": "Consulting Service", "quantity": 1, "itemNetPrice": 100000, "itemTotalPrice": 117000, "itemCurrency": "ILS", "isNoItemVat": false } ], "subTotal": 100000, "totalWithoutVatAmount": 100000, "vatAmount": 17000, "totalAmount": 117000, "comment": "Thank you for your business" }), }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.post( "https://.keep.co.il/seller/api/documents/income", headers={ "Authorization": "Bearer ", }, json={ "type": "invoice", "client": { "name": "Example Buyer", "email": "buyer@example.com", "phone": "0500000002", "socialId": "123456782", }, "currency": "ILS", "docValueDate": "2024-01-15", "dueDate": "2024-02-15", "docLang": "he", "items": [ { "name": "Consulting Service", "quantity": 1, "itemNetPrice": 100000, "itemTotalPrice": 117000, "itemCurrency": "ILS", "isNoItemVat": False, }, ], "subTotal": 100000, "totalWithoutVatAmount": 100000, "vatAmount": 17000, "totalAmount": 117000, "comment": "Thank you for your business", }, ) print(response.text) ``` ### PHP ```php .keep.co.il/seller/api/documents/income'); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Bearer ', ], CURLOPT_POSTFIELDS => $body, ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 202 — Document accepted (success) | Field | Type | Description | | --- | --- | --- | | `payload` | object | | | `payload.id` | string | Created document ID | | `payload.url` | string | URL to download/view the document | ### 400 — Bad Request (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 400, "message": [ "Validation failed" ], "error": "Bad Request" } ``` ### 401 — Unauthorized (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 401, "message": "Unauthorized", "error": "Unauthorized" } ``` ### 403 — Forbidden. The seller cannot issue documents now: invoicing is not set up, the trial has ended, or the seller is closed. (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ### 422 — Unprocessable Entity. Messages include: the client `socialId` is required for documents of 23,600 ILS and above; `Your invoice Israel token is invalid` (with `renewTokenUrl`, where the seller renews the Israel Tax Authority connection); `Record already exists`. (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ### 429 — Too many requests. The body is plain text. (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | - [Get income document](https://docs.payme.io/keep/seller-api/getsellerincomedocument): GET /seller/api/documents/income/{id} — Get income document # Get income document - Sandbox: your partner domain on the Keep sandbox: `GET https://.keep.co.il/seller/api/documents/income/{id}` - Production: your partner domain: `GET https://.keep.co.il/seller/api/documents/income/{id}` ## Credentials - Header `Authorization: Bearer ` Retrieve a specific income document by ID. Documents the seller created in the Keep app are returned too. ## Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | Document ID | ## Code samples ### curl ```bash curl -X GET 'https://.keep.co.il/seller/api/documents/income/' \ -H 'Authorization: Bearer ' ``` ### Node.js ```javascript const response = await fetch("https://.keep.co.il/seller/api/documents/income/", { method: "GET", headers: { "Authorization": "Bearer ", }, }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.get( "https://.keep.co.il/seller/api/documents/income/", headers={ "Authorization": "Bearer ", }, ) print(response.text) ``` ### PHP ```php .keep.co.il/seller/api/documents/income/'); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ', ], ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 200 — Successful response. When no document matches, `payload` is null. (success) | Field | Type | Description | | --- | --- | --- | | `payload` | object | | | `payload.id` | string | | | `payload.sellerId` | string | | | `payload.type` | string | | | `payload.clientId` | string | | | `payload.dueDate` | string | | | `payload.docValueDate` | string | | | `payload.title` | string | | | `payload.docLang` | string | | | `payload.items` | array | Document line items: `itemId`, `quantity`, `itemNetPrice`, `itemTotalPrice`, `itemCurrency`, `isNoItemVat`. The item name is not returned. | | `payload.currency` | string | | | `payload.discount` | number | | | `payload.totalWithoutVatAmount` | number | | | `payload.vatAmount` | number | | | `payload.totalAmount` | number | | | `payload.totalPaid` | number | | | `payload.originTaxDeduction` | number | | | `payload.cash` | object | Cash payment details | | `payload.cc` | object | Credit card payment: `date` and `amount`. | | `payload.bank-transfer` | object | Bank transfer payment details | | `payload.cheque` | object | Cheque payment details | | `payload.e-wallet` | object | E-wallet payment details | | `payload.comment` | string | | | `payload.url` | string | | | `payload.bankDetails` | object | Bank account details for payment | | `payload.docRegulationId` | string | | | `payload.payment` | object | Payment link settings | | `payload.createdAt` | string | | ### 400 — Bad Request. `id` is not a UUID. (error) ### 401 — Unauthorized (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 401, "message": "Unauthorized", "error": "Unauthorized" } ``` ## Partners API - [Obtain access token](https://docs.payme.io/keep/partners-api/gettoken): POST /oauth2/token — Obtain access token # Obtain access token - Sandbox: your partner domain on the Keep sandbox: `POST https://.keep.co.il/oauth2/token` - Production: your partner domain: `POST https://.keep.co.il/oauth2/token` ## Credentials - Request body field `client_secret` (required): Your client secret - Request body field `refresh_token` (optional): Required when `grant_type` is `refresh_token`. A refresh token works once: the response carries a new one, and the old access token stops working. Use this endpoint to obtain an access token using Client Credentials or to refresh an existing token. ## Parameters This endpoint takes no path, query or header parameters. ## Request body Content type: `application/x-www-form-urlencoded` | Field | Type | Required | Description | | --- | --- | --- | --- | | `grant_type` | string | yes | The grant type Allowed values: `client_credentials`, `refresh_token`. | | `scope` | string | no | Space-separated scopes. Send `partner-api` with `grant_type=client_credentials`. The field is optional in the request, but a token issued without a scope is refused with `403` by every Keep endpoint. With `grant_type=refresh_token` it is not needed: the new token keeps the scopes of the original one. | | `client_id` | string | yes | Your client ID | | `client_secret` | string | yes | Your client secret | | `refresh_token` | string | no | Required when `grant_type` is `refresh_token`. A refresh token works once: the response carries a new one, and the old access token stops working. | ### Request example ```json { "grant_type": "client_credentials", "scope": "partner-api", "client_id": "your-client-id", "client_secret": "your-client-secret" } ``` ## Code samples ### curl ```bash curl -X POST 'https://.keep.co.il/oauth2/token' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'scope=partner-api' \ --data-urlencode 'client_id=your-client-id' \ --data-urlencode 'client_secret=your-client-secret' ``` ### Node.js ```javascript const response = await fetch("https://.keep.co.il/oauth2/token", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", }, body: new URLSearchParams({ "grant_type": "client_credentials", "scope": "partner-api", "client_id": "your-client-id", "client_secret": "your-client-secret" }), }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.post( "https://.keep.co.il/oauth2/token", data={ "grant_type": "client_credentials", "scope": "partner-api", "client_id": "your-client-id", "client_secret": "your-client-secret", }, ) print(response.text) ``` ### PHP ```php .keep.co.il/oauth2/token'); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/x-www-form-urlencoded', ], CURLOPT_POSTFIELDS => http_build_query([ 'grant_type' => 'client_credentials', 'scope' => 'partner-api', 'client_id' => 'your-client-id', 'client_secret' => 'your-client-secret', ]), ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 200 — Successful authentication (success) | Field | Type | Description | | --- | --- | --- | | `token_type` | string | | | `access_token` | string | JWT access token | | `refresh_token` | string | Refresh token | | `expires_in` | integer | Access token lifetime in seconds | | `refresh_expires_in` | integer | Refresh token lifetime in seconds | | `scope` | string | Granted scopes | ### 400 — Invalid request. `error` is `invalid_request`, for an unknown refresh token. (error) | Field | Type | Description | | --- | --- | --- | | `error` | string | | | `error_description` | string | | ### 401 — Unauthorized. When `client_id` or `client_secret` is missing, the body is the plain text `Unauthorized`, not JSON. (error) | Field | Type | Description | | --- | --- | --- | | `error` | string | `unauthorized_client` (wrong client ID or secret) or `unauthorized_scope` (scope not granted to this client) | | `error_description` | string | | - [Partners API](https://docs.payme.io/keep/partners-api): The Keep Partner API authenticates with OAuth 2.0 client credentials and refresh tokens. Token endpoint errors return error and error_description. Guard and validation HTTP errors normally include statusCode and message, plus correlationId and category. Retry with exponential backoff. # Partners API PayMe Book-keeping Partner API for integrators. ## Overview > **Authentication Methods** > 1. Client Credentials - Server-to-server authentication > 2. Refresh Token - Token renewal ## Token Lifecycle > 1. Obtain tokens via Client Credentials > 2. Use access_token for API requests > 3. When access_token expires (check expires_in) > 4. Use refresh_token to obtain new access_token > 5. When refresh_token expires, re-authenticate ## Best Practices 1. **Store credentials securely** - Never expose `client_secret` in client-side code 2. **Use HTTPS** - All API requests must use HTTPS 3. **Implement token refresh** - Proactively refresh tokens before expiration 4. **Handle errors gracefully** - Implement retry logic with exponential backoff ## Errors and rate limits - Token endpoint errors return `error` and `error_description`. A wrong client ID or secret returns HTTP 401 `unauthorized_client`; a scope not granted to your client returns HTTP 401 `unauthorized_scope`; an unknown refresh token returns HTTP 400 `invalid_request`. - Guard and validation HTTP errors normally include `statusCode` and `message`, plus `correlationId` and `category`. Some legacy endpoints add `status`; unhandled errors can omit `message`. `message` is a list for validation errors. - A missing or expired access token returns HTTP 401. A token without the required scope returns HTTP 403. - `/api/public/sellers`, `/api/public/expenses` and `/api/public/plans` are rate limited per partner domain and return HTTP 429 when the limit is exceeded. The `429` body is plain text, not the JSON error shape; the `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset` headers show the quota. - Every response carries an `X-Request-Id` header, and an `X-Correlation-Id` header beside it. Quote them when contacting support. If you send your own `X-Request-Id`, it is echoed back. - The document-failure webhook example uses `errorCode` `TAX_AUTHORITY_REJECTED` ("Document rejected by tax authority - invalid VAT number"). - [Create seller](https://docs.payme.io/keep/partners-api/createseller): POST /api/public/sellers/create — Create seller # Create seller - Sandbox: your partner domain on the Keep sandbox: `POST https://.keep.co.il/api/public/sellers/create` - Production: your partner domain: `POST https://.keep.co.il/api/public/sellers/create` ## Credentials - Header `Authorization: Bearer ` Register a new seller account with Israeli business compliance validation. Includes validation for Israeli ID numbers, business registration, and bank account details. ## Parameters This endpoint takes no path, query or header parameters. ## Request body Content type: `application/json` | Field | Type | Required | Description | | --- | --- | --- | --- | | `firstName` | string | yes | Seller's first name, 2 to 250 characters: letters, spaces and the marks `-` `_` `.` `,` `'` `"` `״` `(` `)` `:` `;`. | | `lastName` | string | yes | Seller's last name, 2 to 250 characters: letters, spaces and the marks `-` `_` `.` `,` `'` `"` `״` `(` `)` `:` `;`. | | `email` | string | yes | Seller's primary email address (used for login) | | `contactEmail` | string | yes | Business contact email address | | `password` | string | yes | Account password, at least 6 characters. | | `phone` | string | yes | Phone number, 1 to 250 characters. | | `businessName` | string | yes | Legal business name, at most 250 characters. | | `businessType` | integer | yes | Israeli business type. - `0` Not sure (לא ידוע) - `1` Osek Murshe, sole proprietorship (עוסק מורשה) - `2` Osek Patur, exempt small business (עוסק פטור) - `3` Incorporated company (חברה בע"מ) - `4` Partnership (שותפות) - `6` Non-profit (עמותה) - `7` Limited partnership (שותפות מוגבלת) - `8` Publicly traded company (חברה ציבורית) - `9` Shared cooperative (אגודה שיתופית) - `10` Public benefit company (חברה לתועלת הציבור) | | `businessNumber` | string | yes | Israeli business registration number (ח.פ. / עוסק מורשה). Digits only, at most 9, with a valid check digit. | | `socialId` | string | yes | Israeli ID number (תעודת זהות). Digits only, at most 9, with a valid check digit. | | `industryClassification` | number | no | Industry classification code (optional) | | `bankId` | string | no | Israeli bank code (optional) Digits only. | | `accountNumber` | string | no | Bank account number (optional) Digits only. | | `branchNumber` | string | no | Bank branch number (optional) Digits only. | | `logo` | string | no | Business logo as base64 encoded data URI (optional) | ### Request example ```json { "firstName": "David", "lastName": "Cohen", "email": "david.cohen@example.com", "contactEmail": "seller@example.com", "password": "securePassword123", "phone": "0500000009", "businessName": "Cohen Electronics Ltd", "businessType": 1, "businessNumber": "330988015", "socialId": "123456782", "industryClassification": 12, "bankId": "12", "accountNumber": "123456789012345", "branchNumber": "123", "logo": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." } ``` ## Code samples ### curl ```bash curl -X POST 'https://.keep.co.il/api/public/sellers/create' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ' \ --data-raw '{ "firstName": "David", "lastName": "Cohen", "email": "david.cohen@example.com", "contactEmail": "seller@example.com", "password": "securePassword123", "phone": "0500000009", "businessName": "Cohen Electronics Ltd", "businessType": 1, "businessNumber": "330988015", "socialId": "123456782", "industryClassification": 12, "bankId": "12", "accountNumber": "123456789012345", "branchNumber": "123", "logo": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." }' ``` ### Node.js ```javascript const response = await fetch("https://.keep.co.il/api/public/sellers/create", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": "Bearer ", }, body: JSON.stringify({ "firstName": "David", "lastName": "Cohen", "email": "david.cohen@example.com", "contactEmail": "seller@example.com", "password": "securePassword123", "phone": "0500000009", "businessName": "Cohen Electronics Ltd", "businessType": 1, "businessNumber": "330988015", "socialId": "123456782", "industryClassification": 12, "bankId": "12", "accountNumber": "123456789012345", "branchNumber": "123", "logo": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." }), }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.post( "https://.keep.co.il/api/public/sellers/create", headers={ "Authorization": "Bearer ", }, json={ "firstName": "David", "lastName": "Cohen", "email": "david.cohen@example.com", "contactEmail": "seller@example.com", "password": "securePassword123", "phone": "0500000009", "businessName": "Cohen Electronics Ltd", "businessType": 1, "businessNumber": "330988015", "socialId": "123456782", "industryClassification": 12, "bankId": "12", "accountNumber": "123456789012345", "branchNumber": "123", "logo": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...", }, ) print(response.text) ``` ### PHP ```php .keep.co.il/api/public/sellers/create'); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Bearer ', ], CURLOPT_POSTFIELDS => $body, ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 201 — Seller created successfully (success) | Field | Type | Description | | --- | --- | --- | | `payload` | object | | | `payload.sellerId` | string | Newly created seller's UUID | ```json { "payload": { "sellerId": "9a5e7898-067e-4c0c-a50f-5f8d83e7c686" } } ``` ### 400 — Bad Request. Returned for validation errors, and for these onboarding refusals: - `Social ID is invalid` — a Keep seller already uses this ID number. - `The email is invalid. Please try again` — a Keep account already uses this email. Other onboarding errors are returned as `400` with their own message. (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 400, "message": [ "Validation failed" ], "error": "Bad Request" } ``` ### 401 — Unauthorized (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | | | `message` | string | | ```json { "statusCode": 401, "message": "Unauthorized" } ``` - [Get seller](https://docs.payme.io/keep/partners-api/getsellerbyid): GET /api/public/sellers/{sellerId} — Get seller # Get seller - Sandbox: your partner domain on the Keep sandbox: `GET https://.keep.co.il/api/public/sellers/{sellerId}` - Production: your partner domain: `GET https://.keep.co.il/api/public/sellers/{sellerId}` ## Credentials - Header `Authorization: Bearer ` Retrieve seller information by Keep seller UUID or by MPL. Returns seller details including business information and timestamps. ## Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `sellerId` | path | string | yes | Seller UUID or MPL ID | ## Code samples ### curl ```bash curl -X GET 'https://.keep.co.il/api/public/sellers/' \ -H 'Authorization: Bearer ' ``` ### Node.js ```javascript const response = await fetch("https://.keep.co.il/api/public/sellers/", { method: "GET", headers: { "Authorization": "Bearer ", }, }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.get( "https://.keep.co.il/api/public/sellers/", headers={ "Authorization": "Bearer ", }, ) print(response.text) ``` ### PHP ```php .keep.co.il/api/public/sellers/'); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ', ], ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 200 — Seller retrieved successfully. When no seller matches, `payload` is null. (success) | Field | Type | Description | | --- | --- | --- | | `payload` | object | | | `payload.id` | string | Seller UUID | | `payload.firstName` | string | Seller's first name | | `payload.lastName` | string | Seller's last name | | `payload.email` | string | Primary email address | | `payload.contactEmail` | string | Business contact email | | `payload.phone` | string | Phone number | | `payload.businessName` | string | Legal business name | | `payload.businessType` | integer | Israeli business type. - `0` Not sure (לא ידוע) - `1` Osek Murshe, sole proprietorship (עוסק מורשה) - `2` Osek Patur, exempt small business (עוסק פטור) - `3` Incorporated company (חברה בע"מ) - `4` Partnership (שותפות) - `6` Non-profit (עמותה) - `7` Limited partnership (שותפות מוגבלת) - `8` Publicly traded company (חברה ציבורית) - `9` Shared cooperative (אגודה שיתופית) - `10` Public benefit company (חברה לתועלת הציבור) | | `payload.businessNumber` | string | Israeli business registration number | | `payload.socialId` | string | Israeli ID number | | `payload.createdAt` | string | Account creation timestamp | | `payload.updatedAt` | string | Last update timestamp | | `payload.sellerStatus` | integer | `-1` new, `0` closed, `1` active | | `payload.industryClassification` | integer | | ```json { "payload": { "id": "97bdce55-b2a2-450d-8d29-1dcf6bbcc419", "firstName": "David", "lastName": "Cohen", "email": "david.cohen@example.com", "contactEmail": "seller@example.com", "phone": "0500000009", "businessName": "Cohen Electronics Ltd", "businessType": 1, "businessNumber": "330988015", "socialId": "123456782", "createdAt": "2026-01-22T09:19:54.264Z", "updatedAt": "2026-01-22T09:19:54.403Z" } } ``` ### 401 — Unauthorized (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | | | `message` | string | | ```json { "statusCode": 401, "message": "Unauthorized" } ``` - [Get available plans](https://docs.payme.io/keep/partners-api/getpartnerplans): GET /api/public/plans — Get available plans # Get available plans - Sandbox: your partner domain on the Keep sandbox: `GET https://.keep.co.il/api/public/plans` - Production: your partner domain: `GET https://.keep.co.il/api/public/plans` ## Credentials - Header `Authorization: Bearer ` Retrieve the plans available to the authenticated partner. Only plans that are currently offered for selection are returned; retired plans are not. ## Parameters This endpoint takes no path, query or header parameters. ## Code samples ### curl ```bash curl -X GET 'https://.keep.co.il/api/public/plans' \ -H 'Authorization: Bearer ' ``` ### Node.js ```javascript const response = await fetch("https://.keep.co.il/api/public/plans", { method: "GET", headers: { "Authorization": "Bearer ", }, }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.get( "https://.keep.co.il/api/public/plans", headers={ "Authorization": "Bearer ", }, ) print(response.text) ``` ### PHP ```php .keep.co.il/api/public/plans'); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ', ], ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 200 — Plans retrieved successfully (success) | Field | Type | Description | | --- | --- | --- | | `payload` | object | | | `payload.items` | array | | | `payload.items[].id` | string | Unique identifier for the plan | | `payload.items[].name` | string | Display name of the plan | | `payload.items[].price` | number | Plan price in the partner's currency | ```json { "payload": { "items": [ { "id": "90abd0eb-c374-4a2b-829e-681fba0cdbee", "name": "PaturBasic", "price": 39.9 }, { "id": "29b1f228-c779-4de3-bb99-aa8e34f29ddc", "name": "PaturPremium", "price": 105 }, { "id": "3d653770-6376-40a5-b98e-17c598f1d7d8", "name": "MursheBasic", "price": 39.9 }, { "id": "c2249657-fe98-49ae-950a-3bdf28cdbfee", "name": "MurshePremium", "price": 228 } ] } } ``` ### 401 — Unauthorized (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | | | `message` | string | | ```json { "statusCode": 401, "message": "Unauthorized" } ``` - [List expenses](https://docs.payme.io/keep/partners-api/listpublicexpenses): GET /api/public/expenses — List expenses # List expenses - Sandbox: your partner domain on the Keep sandbox: `GET https://.keep.co.il/api/public/expenses` - Production: your partner domain: `GET https://.keep.co.il/api/public/expenses` ## Credentials - Header `Authorization: Bearer ` Retrieve expense records for a seller with optional date filtering and pagination. **Seller identification:** Same rules as the upload endpoint — provide `sellerId` alone, or `socialId` + `email`. **Date filtering:** `valueDateStart` and `valueDateEnd` filter on the expense value date (not creation date). Dates must be ISO format (`YYYY-MM-DD`) and `valueDateStart` must be ≤ `valueDateEnd`. **Pagination:** Defaults to `page=0`, `limit=10`. Maximum `limit=500`. Order of returned items is not guaranteed. ## Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `sellerId` | query | string | no | Seller UUID (use this OR socialId + email) | | `socialId` | query | integer | no | Seller ID number, digits only, sent as a number (must be paired with email). | | `email` | query | string | no | Seller email address (must be paired with socialId) | | `valueDateStart` | query | string | no | Filter expenses from this value date (inclusive, YYYY-MM-DD) | | `valueDateEnd` | query | string | no | Filter expenses up to this value date (inclusive, YYYY-MM-DD) | | `page` | query | integer | no | Page number (zero-based). Minimum 0, default 0. | | `limit` | query | integer | no | Items per page. Positive number, at most 500; use a whole-number item count. Default 10. | ## Code samples ### curl ```bash curl -X GET 'https://.keep.co.il/api/public/expenses' \ -H 'Authorization: Bearer ' ``` ### Node.js ```javascript const response = await fetch("https://.keep.co.il/api/public/expenses", { method: "GET", headers: { "Authorization": "Bearer ", }, }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.get( "https://.keep.co.il/api/public/expenses", headers={ "Authorization": "Bearer ", }, ) print(response.text) ``` ### PHP ```php .keep.co.il/api/public/expenses'); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ', ], ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 200 — Expenses retrieved successfully (success) | Field | Type | Description | | --- | --- | --- | | `payload` | object | | | `payload.total` | integer | Total number of matching expenses | | `payload.page` | integer | Current page number | | `payload.limit` | integer | Items per page | | `payload.items` | array | | | `payload.items[].id` | string | Expense record UUID | | `payload.items[].capturedDate` | string | Timestamp when the expense was captured | | `payload.items[].valueDate` | string | Expense value date | | `payload.items[].sellerId` | string | Seller UUID | | `payload.items[].totalAmount` | number | Total expense amount | | `payload.items[].vatAmount` | number | VAT amount | | `payload.items[].currency` | string | Currency code | | `payload.items[].bookkeeperRevisionStatus` | string | Bookkeeper revision status | | `payload.items[].docRegulationId` | string | Document regulation ID | | `payload.items[].docType` | string | Document type | ```json { "payload": { "total": 1, "page": 0, "limit": 10, "items": [ { "id": "50c6b740-874a-4f54-9669-9a60024be4ed", "capturedDate": "2024-06-20T09:35:36.326Z", "valueDate": "2024-06-20T00:00:00.000Z", "sellerId": "a6a9700f-8571-4f9b-bfae-ba943fb96982", "totalAmount": 15200, "vatAmount": 2209, "currency": "ILS", "bookkeeperRevisionStatus": "approved-and-classified", "docRegulationId": "1262", "docType": "invrec" } ] } } ``` ### 400 — Bad Request (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 400, "message": [ "Validation failed" ], "error": "Bad Request" } ``` ### 401 — Unauthorized (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | | | `message` | string | | ```json { "statusCode": 401, "message": "Unauthorized" } ``` ### 403 — The seller does not belong to your partner account. (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ### 422 — Unprocessable Entity. Message: `Could not resolve seller` — the identifiers match no seller. (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 422, "message": "Bad seller configuration. Please contact support!", "error": "Unprocessable Entity" } ``` - [Upload expense document](https://docs.payme.io/keep/partners-api/uploadpublicexpense): POST /api/public/expenses — Upload expense document # Upload expense document - Sandbox: your partner domain on the Keep sandbox: `POST https://.keep.co.il/api/public/expenses` - Production: your partner domain: `POST https://.keep.co.il/api/public/expenses` ## Credentials - Header `Authorization: Bearer ` Upload an expense document for a seller via a publicly accessible file URL. **Seller identification:** Exactly one method must be used per request: - **Option A:** `sellerId` (UUID) - **Option B:** `socialId` + `email` Providing neither returns HTTP 400. **Supported file formats:** PDF, JPG, PNG. ## Parameters This endpoint takes no path, query or header parameters. ## Request body Content type: `application/json` | Field | Type | Required | Description | | --- | --- | --- | --- | | `sellerId` | string | no | Seller UUID (use this OR socialId + email, not both) | | `socialId` | number | no | Seller social/business ID number (must be paired with email) | | `email` | string | no | Seller email address (must be paired with socialId) | | `file` | string | yes | Publicly accessible URL of the expense document (PDF, JPG, or PNG) | ### Request example ```json { "sellerId": "a6a9700f-8571-4f9b-bfae-ba943fb96982", "file": "https://i0.wp.com/avatar-management--avatars.us-west-2.prod.public.atl-paas.net/initials/AK-3.png?ssl=1" } ``` ## Code samples ### curl ```bash curl -X POST 'https://.keep.co.il/api/public/expenses' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ' \ --data-raw '{ "sellerId": "a6a9700f-8571-4f9b-bfae-ba943fb96982", "file": "https://i0.wp.com/avatar-management--avatars.us-west-2.prod.public.atl-paas.net/initials/AK-3.png?ssl=1" }' ``` ### Node.js ```javascript const response = await fetch("https://.keep.co.il/api/public/expenses", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": "Bearer ", }, body: JSON.stringify({ "sellerId": "a6a9700f-8571-4f9b-bfae-ba943fb96982", "file": "https://i0.wp.com/avatar-management--avatars.us-west-2.prod.public.atl-paas.net/initials/AK-3.png?ssl=1" }), }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.post( "https://.keep.co.il/api/public/expenses", headers={ "Authorization": "Bearer ", }, json={ "sellerId": "a6a9700f-8571-4f9b-bfae-ba943fb96982", "file": "https://i0.wp.com/avatar-management--avatars.us-west-2.prod.public.atl-paas.net/initials/AK-3.png?ssl=1", }, ) print(response.text) ``` ### PHP ```php .keep.co.il/api/public/expenses'); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Bearer ', ], CURLOPT_POSTFIELDS => $body, ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 201 — Expense document uploaded successfully (success) | Field | Type | Description | | --- | --- | --- | | `payload` | object | | | `payload.id` | string | Unique identifier for the created expense record | | `payload.capturedDate` | string | Timestamp when the expense was captured | | `payload.sellerId` | string | Resolved seller UUID | ```json { "payload": { "id": "a3504d9d-c187-48a0-8274-bea3b48e5663", "capturedDate": "2026-02-02T13:05:54.170Z", "sellerId": "a6a9700f-8571-4f9b-bfae-ba943fb96982" } } ``` ### 400 — Validation error (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 400, "message": [ "socialId must be a number conforming to the specified constraints", "socialId should not be empty", "email must be an email", "email should not be empty", "sellerId must be a UUID", "sellerId should not be empty" ], "error": "Bad Request" } ``` ### 401 — Unauthorized (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | | | `message` | string | | ```json { "statusCode": 401, "message": "Unauthorized" } ``` ### 422 — Unprocessable entity — seller not resolved or file URL unreachable (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 422, "message": "Could not resolve seller", "error": "Unprocessable Entity" } ``` - [Update expense](https://docs.payme.io/keep/partners-api/updatepublicexpense): PATCH /api/public/expenses/{expenseId} — Update expense # Update expense - Sandbox: your partner domain on the Keep sandbox: `PATCH https://.keep.co.il/api/public/expenses/{expenseId}` - Production: your partner domain: `PATCH https://.keep.co.il/api/public/expenses/{expenseId}` ## Credentials - Header `Authorization: Bearer ` Partially update an existing expense document. Only expenses with `pending` status can be updated. The partner can only update expenses within their own scope, and the expense must belong to the provided `sellerId`. **Immutable fields** (ignored if provided): `id`, `uid`, `partnerId`, `createdAt`, `updatedAt`, `updatedBy`, `seller`, `supplierSnapshot`, `vatReportSnapshot`, `isAbleToAutoApprove`, `status`. ## Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `expenseId` | path | string | yes | Expense UUID to update | ## Request body Content type: `application/json` | Field | Type | Required | Description | | --- | --- | --- | --- | | `sellerId` | string | yes | Seller UUID the expense belongs to | | `valueDate` | string | no | Expense value date (ISO 8601 UTC) | | `totalAmount` | number | no | Total expense amount, minimum 0. | | `vatAmount` | number | no | VAT amount (must be ≤ totalAmount), minimum 0. Required when `totalAmount` is sent. | | `currency` | string | no | Currency code. Allowed values: `ILS`, `USD`, `EUR`, `GBP`, `TRY`, `CHF`, `SEK`, `NOK`, `CAD`, `ZAR`, `JPY`, `AUD`, `AED`, `ARS`, `BHD`, `BRL`, `CNY`, `INR`, `KRW`, `KWD`, `KZT`, `MXN`, `NGN`, `PLN`, `RSD`, `RUB`, `SAR`, `UAH`, `PHP`, `VND`. | | `docType` | string | no | Document type. Allowed values: `invoice`, `invrec`, `receipt`, `deal`, `unknown`. | | `docRegulationId` | string | no | Document regulation ID | | `classification` | integer | no | Classification ID from the Keep expense classification table. An unknown ID is refused with `422` `Invalid classification`. | | `deductibleIncomeTaxPercent` | number | no | Deductible income tax percentage (0–100). Decimals are accepted. | | `deductibleVatPercent` | number | no | Deductible VAT percentage (0–100). Decimals are accepted. | | `assetVatRefundPercent` | number | no | Asset VAT refund percentage (0–100). Decimals are accepted. | | `comment` | string | no | Optional partner note, at most 1024 characters. | | `supplierName` | string | no | Supplier name, at most 256 characters. Applied only together with `supplierVatId`. | | `supplierVatId` | string | no | Supplier VAT ID, digits. An invalid ID is refused with `422` `Provided supplier ID is invalid`. | ### Request example ```json { "sellerId": "a6a9700f-8571-4f9b-bfae-ba943fb96982", "valueDate": "2025-10-28T00:00:00.000Z", "totalAmount": 15000, "vatAmount": 2288, "currency": "ILS", "docType": "invrec", "docRegulationId": "5132277", "classification": 6, "deductibleIncomeTaxPercent": 100, "deductibleVatPercent": 100, "assetVatRefundPercent": 0, "comment": "Optional partner note", "supplierName": "Supplier Ltd", "supplierVatId": "123456789" } ``` ## Code samples ### curl ```bash curl -X PATCH 'https://.keep.co.il/api/public/expenses/' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ' \ --data-raw '{ "sellerId": "a6a9700f-8571-4f9b-bfae-ba943fb96982", "valueDate": "2025-10-28T00:00:00.000Z", "totalAmount": 15000, "vatAmount": 2288, "currency": "ILS", "docType": "invrec", "docRegulationId": "5132277", "classification": 6, "deductibleIncomeTaxPercent": 100, "deductibleVatPercent": 100, "assetVatRefundPercent": 0, "comment": "Optional partner note", "supplierName": "Supplier Ltd", "supplierVatId": "123456789" }' ``` ### Node.js ```javascript const response = await fetch("https://.keep.co.il/api/public/expenses/", { method: "PATCH", headers: { "Content-Type": "application/json", "Authorization": "Bearer ", }, body: JSON.stringify({ "sellerId": "a6a9700f-8571-4f9b-bfae-ba943fb96982", "valueDate": "2025-10-28T00:00:00.000Z", "totalAmount": 15000, "vatAmount": 2288, "currency": "ILS", "docType": "invrec", "docRegulationId": "5132277", "classification": 6, "deductibleIncomeTaxPercent": 100, "deductibleVatPercent": 100, "assetVatRefundPercent": 0, "comment": "Optional partner note", "supplierName": "Supplier Ltd", "supplierVatId": "123456789" }), }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.patch( "https://.keep.co.il/api/public/expenses/", headers={ "Authorization": "Bearer ", }, json={ "sellerId": "a6a9700f-8571-4f9b-bfae-ba943fb96982", "valueDate": "2025-10-28T00:00:00.000Z", "totalAmount": 15000, "vatAmount": 2288, "currency": "ILS", "docType": "invrec", "docRegulationId": "5132277", "classification": 6, "deductibleIncomeTaxPercent": 100, "deductibleVatPercent": 100, "assetVatRefundPercent": 0, "comment": "Optional partner note", "supplierName": "Supplier Ltd", "supplierVatId": "123456789", }, ) print(response.text) ``` ### PHP ```php .keep.co.il/api/public/expenses/'); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'PATCH', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Bearer ', ], CURLOPT_POSTFIELDS => $body, ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 200 — Expense updated successfully (success) | Field | Type | Description | | --- | --- | --- | | `payload` | object | | | `payload.id` | string | Expense UUID | | `payload.sellerId` | string | Seller UUID | | `payload.valueDate` | string | Expense value date | | `payload.totalAmount` | number | Total expense amount | | `payload.vatAmount` | number | VAT amount | | `payload.currency` | string | Currency code | | `payload.docType` | string | Document type | | `payload.docRegulationId` | string | Document regulation ID | | `payload.classification` | integer | Classification ID | | `payload.capturedDate` | string | Timestamp when expense was captured | ```json { "payload": { "id": "edc855f7-cb7c-4d82-8c26-baf5c296d391", "sellerId": "a6a9700f-8571-4f9b-bfae-ba943fb96982", "valueDate": "2025-10-28T00:00:00.000Z", "totalAmount": 15000, "vatAmount": 2288, "currency": "ILS", "docType": "invrec", "docRegulationId": "5132277", "classification": 6, "capturedDate": "2025-10-28T09:13:37.423Z" } } ``` ### 400 — Validation error, and the message `Bad identifier` when the expense does not exist. (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 400, "message": [ "Validation failed" ], "error": "Bad Request" } ``` ### 401 — Unauthorized (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | | | `message` | string | | ```json { "statusCode": 401, "message": "Unauthorized" } ``` ### 403 — Partner is not authorized to update this expense (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | ### 422 — Unprocessable Entity. Messages: `Only expenses with pending status can be updated`, `Could not resolve seller`, `Provided supplier ID is invalid`, `Invalid classification`. (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ### 429 — Rate limit exceeded (error) - [Update seller](https://docs.payme.io/keep/partners-api/updatesellerbyid): PUT /api/public/sellers/{sellerId}/update — Update seller # Update seller - Sandbox: your partner domain on the Keep sandbox: `PUT https://.keep.co.il/api/public/sellers/{sellerId}/update` - Production: your partner domain: `PUT https://.keep.co.il/api/public/sellers/{sellerId}/update` ## Credentials - Header `Authorization: Bearer ` Replace a seller's details. Send all required fields on every request. ## Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `sellerId` | path | string | yes | Seller UUID (v4), as returned by Create seller or Get seller. An MPL is not accepted here. | ## Request body Content type: `application/json` | Field | Type | Required | Description | | --- | --- | --- | --- | | `firstName` | string | yes | Seller's first name, 2 to 250 characters: letters, spaces and the marks `-` `_` `.` `,` `'` `"` `״` `(` `)` `:` `;`. | | `lastName` | string | yes | Seller's last name, 2 to 250 characters: letters, spaces and the marks `-` `_` `.` `,` `'` `"` `״` `(` `)` `:` `;`. | | `email` | string | yes | Primary email address | | `contactEmail` | string | yes | Business contact email | | `phone` | string | yes | Phone number, 1 to 250 characters. | | `businessName` | string | yes | Legal business name, at most 250 characters. | | `businessType` | integer | yes | Israeli business type. - `0` Not sure (לא ידוע) - `1` Osek Murshe, sole proprietorship (עוסק מורשה) - `2` Osek Patur, exempt small business (עוסק פטור) - `3` Incorporated company (חברה בע"מ) - `4` Partnership (שותפות) - `6` Non-profit (עמותה) - `7` Limited partnership (שותפות מוגבלת) - `8` Publicly traded company (חברה ציבורית) - `9` Shared cooperative (אגודה שיתופית) - `10` Public benefit company (חברה לתועלת הציבור) | | `businessNumber` | string | yes | Israeli business registration number (ח.פ. / עוסק מורשה). Digits only, at most 9, with a valid check digit. | | `socialId` | string | yes | Israeli ID number (תעודת זהות). Digits only, at most 9, with a valid check digit. | | `industryClassification` | number | no | Industry classification code | | `bankId` | string | no | Israeli bank code Digits only. | | `accountNumber` | string | no | Bank account number Digits only. | | `branchNumber` | string | no | Bank branch number Digits only. | | `logo` | string | no | Business logo as base64 encoded data URI | ### Request example ```json { "firstName": "David", "lastName": "Cohen", "email": "david.cohen1115@example.com", "contactEmail": "seller@example.com", "phone": "0500000008", "businessName": "Cohen Electronics", "businessType": 2, "businessNumber": "330988015", "socialId": "123456782", "bankId": "12", "accountNumber": "123456789012345", "branchNumber": "123", "logo": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." } ``` ## Code samples ### curl ```bash curl -X PUT 'https://.keep.co.il/api/public/sellers//update' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ' \ --data-raw '{ "firstName": "David", "lastName": "Cohen", "email": "david.cohen1115@example.com", "contactEmail": "seller@example.com", "phone": "0500000008", "businessName": "Cohen Electronics", "businessType": 2, "businessNumber": "330988015", "socialId": "123456782", "bankId": "12", "accountNumber": "123456789012345", "branchNumber": "123", "logo": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." }' ``` ### Node.js ```javascript const response = await fetch("https://.keep.co.il/api/public/sellers//update", { method: "PUT", headers: { "Content-Type": "application/json", "Authorization": "Bearer ", }, body: JSON.stringify({ "firstName": "David", "lastName": "Cohen", "email": "david.cohen1115@example.com", "contactEmail": "seller@example.com", "phone": "0500000008", "businessName": "Cohen Electronics", "businessType": 2, "businessNumber": "330988015", "socialId": "123456782", "bankId": "12", "accountNumber": "123456789012345", "branchNumber": "123", "logo": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." }), }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.put( "https://.keep.co.il/api/public/sellers//update", headers={ "Authorization": "Bearer ", }, json={ "firstName": "David", "lastName": "Cohen", "email": "david.cohen1115@example.com", "contactEmail": "seller@example.com", "phone": "0500000008", "businessName": "Cohen Electronics", "businessType": 2, "businessNumber": "330988015", "socialId": "123456782", "bankId": "12", "accountNumber": "123456789012345", "branchNumber": "123", "logo": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...", }, ) print(response.text) ``` ### PHP ```php .keep.co.il/api/public/sellers//update'); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'PUT', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Bearer ', ], CURLOPT_POSTFIELDS => $body, ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 200 — Seller updated successfully (success) ```json {} ``` ### 400 — Bad Request. Returned for validation errors, when `sellerId` is not a UUID v4, and with the message `Bad identifier` when the seller does not exist. (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 400, "message": [ "Validation failed" ], "error": "Bad Request" } ``` ### 401 — Unauthorized (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | | | `message` | string | | ```json { "statusCode": 401, "message": "Unauthorized" } ``` ### 403 — The seller does not belong to your partner account (error) - [Set seller billing plan](https://docs.payme.io/keep/partners-api/setsellerplan): POST /api/public/plans/activate — Set seller billing plan # Set seller billing plan - Sandbox: your partner domain on the Keep sandbox: `POST https://.keep.co.il/api/public/plans/activate` - Production: your partner domain: `POST https://.keep.co.il/api/public/plans/activate` ## Credentials - Header `Authorization: Bearer ` Assign a billing plan to a seller with payer-based activation flow. **Payer modes:** - `partner` — No credit card is required. The plan is normally activated at once. It is scheduled instead of activated when the seller is on a free plan within the trial or the sign-up month, and when a no-cost plan is chosen on days 20–31 of a month; the response is still `activated`, and the plan takes effect at the scheduled date. - `seller` — If the seller already has a credit card on file, the plan is activated immediately. If not, a credit card URL is returned and the plan activates once the seller completes payment. **Pending response** (`payer` is `seller` and no card is on file): ```json { "payload": { "status": "pending", "message": "Please complete payment to activate plan", "creditCardUrl": "" } } ``` ## Parameters This endpoint takes no path, query or header parameters. ## Request body Content type: `application/json` | Field | Type | Required | Description | | --- | --- | --- | --- | | `sellerId` | string | yes | Seller UUID | | `planId` | string | yes | Plan UUID, from Get available plans | | `payer` | string | yes | Who pays for the plan. 'partner' = immediate activation, 'seller' = may require credit card. Allowed values: `partner`, `seller`. | ### Request example ```json { "sellerId": "a6a9700f-8571-4f9b-bfae-ba943fb96982", "planId": "3d653770-6376-40a5-b98e-17c598f1d7d8", "payer": "partner" } ``` ## Code samples ### curl ```bash curl -X POST 'https://.keep.co.il/api/public/plans/activate' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ' \ --data-raw '{ "sellerId": "a6a9700f-8571-4f9b-bfae-ba943fb96982", "planId": "3d653770-6376-40a5-b98e-17c598f1d7d8", "payer": "partner" }' ``` ### Node.js ```javascript const response = await fetch("https://.keep.co.il/api/public/plans/activate", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": "Bearer ", }, body: JSON.stringify({ "sellerId": "a6a9700f-8571-4f9b-bfae-ba943fb96982", "planId": "3d653770-6376-40a5-b98e-17c598f1d7d8", "payer": "partner" }), }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.post( "https://.keep.co.il/api/public/plans/activate", headers={ "Authorization": "Bearer ", }, json={ "sellerId": "a6a9700f-8571-4f9b-bfae-ba943fb96982", "planId": "3d653770-6376-40a5-b98e-17c598f1d7d8", "payer": "partner", }, ) print(response.text) ``` ### PHP ```php .keep.co.il/api/public/plans/activate'); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Bearer ', ], CURLOPT_POSTFIELDS => $body, ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 201 — Plan set successfully (success) | Field | Type | Description | | --- | --- | --- | | `payload` | object | | | `payload.status` | string | 'activated' when plan is active immediately, 'pending' when seller must complete payment first. | | `payload.message` | string | Human-readable message (present when status is 'pending') | | `payload.creditCardUrl` | string | URL for seller to submit credit card details (present when status is 'pending') | ```json { "payload": { "status": "activated" } } ``` ### 400 — Bad Request. Returned for validation errors, and with the message `Bad seller identifier` when the seller is unknown. (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 400, "message": [ "Validation failed" ], "error": "Bad Request" } ``` ### 401 — Unauthorized (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | | | `message` | string | | ```json { "statusCode": 401, "message": "Unauthorized" } ``` ### 403 — The seller does not belong to your partner account (error) ### 422 — Unprocessable Entity (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 422, "message": "Bad seller configuration. Please contact support!", "error": "Unprocessable Entity" } ``` - [List income documents](https://docs.payme.io/keep/partners-api/listincomedocuments): GET /partner/api/documents/income — List income documents # List income documents - Sandbox: your partner domain on the Keep sandbox: `GET https://.keep.co.il/partner/api/documents/income` - Production: your partner domain: `GET https://.keep.co.il/partner/api/documents/income` ## Credentials - Header `Authorization: Bearer ` Retrieve a list of income documents for a seller ## Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `sellerPaymeId` | query | string | no | Seller PayMe ID. One of `sellerPaymeId` or `sellerId` is required. | | `sellerId` | query | string | no | Keep seller UUID (v4). One of `sellerPaymeId` or `sellerId` is required. | | `docNum` | query | string | no | Document number, digits only. Matches the regulation number of the document (`docRegulationId`). | | `page` | query | integer | no | Page number. Minimum 0, default 0. | | `limit` | query | integer | no | Items per page. Positive number, at most 500; use a whole-number item count. Default 10. | ## Code samples ### curl ```bash curl -X GET 'https://.keep.co.il/partner/api/documents/income' \ -H 'Authorization: Bearer ' ``` ### Node.js ```javascript const response = await fetch("https://.keep.co.il/partner/api/documents/income", { method: "GET", headers: { "Authorization": "Bearer ", }, }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.get( "https://.keep.co.il/partner/api/documents/income", headers={ "Authorization": "Bearer ", }, ) print(response.text) ``` ### PHP ```php .keep.co.il/partner/api/documents/income'); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ', ], ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 200 — Successful response (success) | Field | Type | Description | | --- | --- | --- | | `payload` | object | | | `payload.page` | integer | | | `payload.limit` | integer | | | `payload.total` | integer | | | `payload.items` | array | Each item also contains the fields sent when the document was created. | | `payload.items[].id` | string | | | `payload.items[].url` | string | | ### 400 — Bad Request. Messages include `At least one of sellerPaymeId or sellerId should exists` and `Bad seller identifier`. (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 400, "message": [ "Validation failed" ], "error": "Bad Request" } ``` ### 401 — Unauthorized (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | | | `message` | string | | ```json { "statusCode": 401, "message": "Unauthorized" } ``` - [Create manual income document](https://docs.payme.io/keep/partners-api/createmanualincomedocument): POST /partner/api/documents/income/manual — Create manual income document # Create manual income document - Sandbox: your partner domain on the Keep sandbox: `POST https://.keep.co.il/partner/api/documents/income/manual` - Production: your partner domain: `POST https://.keep.co.il/partner/api/documents/income/manual` ## Credentials - Header `Authorization: Bearer ` Create a new income document manually ## Parameters This endpoint takes no path, query or header parameters. ## Request body Content type: `application/json` | Field | Type | Required | Description | | --- | --- | --- | --- | | `seller_email` | string | yes | Seller's email address | | `seller_social_id_number` | string | yes | Seller's ID or business number, 9 digits | | `osek_type` | integer | yes | `1` Osek Murshe or `2` Osek Patur. Must match the seller's record. | | `doc_type` | integer | yes | Send a supported numeric document code: `300` deal invoice, `305` invoice, `320` invoice with receipt, `330` refund, `400` receipt, `600` offer | | `value_date` | string | yes | Document date: `YYYY-MM-DD`, `DD.M.YYYY` or `DD.MM.YYYY` | | `currency` | string | yes | Allowed values: `ILS`. | | `doc_language` | string | yes | Allowed values: `he`. | | `client_type` | string | yes | Allowed values: `ConsumerPrivate`, `Business`. | | `client_name` | string | yes | Client name | | `client_id` | string | no | Client's ID or business number, 9 digits | | `document_number` | string | yes | Document number. Must be unique for the seller and must not start with `514` or `515`. | | `document_id` | string | no | Your identifier for the document | | `total_sum_including_vat` | number | yes | Total including VAT, in shekels | | `total_vat_number` | number | yes | VAT amount, in shekels | | `item_description` | string | yes | Item description | | `item_type` | string | yes | Allowed values: `Service`, `PhysicalGoods`, `VirtualGoods`. | | `sale_currency` | string | yes | Allowed values: `ILS`. | | `sale_vat_rule_vat_exempt` | boolean | yes | `true` when the item is VAT exempt | | `unit_price` | number | yes | Unit price before VAT, in shekels | | `quantity` | number | yes | Quantity | | `sum_amount_paid_with_this_payment_method` | number | yes | Amount paid, in shekels | | `payment_methods` | string | yes | Allowed values: `bank_transfer`, `credit_card`, `pay_pal`. | | `origin_tax_deduction` | number | yes | Tax deducted at source, in shekels. Send `0` when there is none. | | `file_id` | string | no | ID of an already uploaded file. Required when `file_name` and `file_path` are not sent. | | `file_name` | string | no | Document file name. Required with `file_path` when `file_id` is not sent. | | `file_path` | string | no | Object key of the file in Keep storage — not a URL. Required with `file_name` when `file_id` is not sent. | ### Request example ```json { "seller_email": "seller@example.com", "seller_social_id_number": "123456782", "osek_type": 1, "doc_type": 320, "value_date": "2024-01-15", "currency": "ILS", "doc_language": "he", "client_type": "Business", "client_name": "Israel Israeli", "client_id": "123456782", "document_number": "10001", "total_sum_including_vat": 1170, "total_vat_number": 170, "item_description": "Consulting Service", "item_type": "Service", "sale_currency": "ILS", "sale_vat_rule_vat_exempt": false, "unit_price": 1000, "quantity": 1, "sum_amount_paid_with_this_payment_method": 1170, "payment_methods": "bank_transfer", "origin_tax_deduction": 0, "file_name": "invoice.pdf", "file_path": "uploads/invoices/invoice.pdf" } ``` ## Code samples ### curl ```bash curl -X POST 'https://.keep.co.il/partner/api/documents/income/manual' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ' \ --data-raw '{ "seller_email": "seller@example.com", "seller_social_id_number": "123456782", "osek_type": 1, "doc_type": 320, "value_date": "2024-01-15", "currency": "ILS", "doc_language": "he", "client_type": "Business", "client_name": "Israel Israeli", "client_id": "123456782", "document_number": "10001", "total_sum_including_vat": 1170, "total_vat_number": 170, "item_description": "Consulting Service", "item_type": "Service", "sale_currency": "ILS", "sale_vat_rule_vat_exempt": false, "unit_price": 1000, "quantity": 1, "sum_amount_paid_with_this_payment_method": 1170, "payment_methods": "bank_transfer", "origin_tax_deduction": 0, "file_name": "invoice.pdf", "file_path": "uploads/invoices/invoice.pdf" }' ``` ### Node.js ```javascript const response = await fetch("https://.keep.co.il/partner/api/documents/income/manual", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": "Bearer ", }, body: JSON.stringify({ "seller_email": "seller@example.com", "seller_social_id_number": "123456782", "osek_type": 1, "doc_type": 320, "value_date": "2024-01-15", "currency": "ILS", "doc_language": "he", "client_type": "Business", "client_name": "Israel Israeli", "client_id": "123456782", "document_number": "10001", "total_sum_including_vat": 1170, "total_vat_number": 170, "item_description": "Consulting Service", "item_type": "Service", "sale_currency": "ILS", "sale_vat_rule_vat_exempt": false, "unit_price": 1000, "quantity": 1, "sum_amount_paid_with_this_payment_method": 1170, "payment_methods": "bank_transfer", "origin_tax_deduction": 0, "file_name": "invoice.pdf", "file_path": "uploads/invoices/invoice.pdf" }), }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.post( "https://.keep.co.il/partner/api/documents/income/manual", headers={ "Authorization": "Bearer ", }, json={ "seller_email": "seller@example.com", "seller_social_id_number": "123456782", "osek_type": 1, "doc_type": 320, "value_date": "2024-01-15", "currency": "ILS", "doc_language": "he", "client_type": "Business", "client_name": "Israel Israeli", "client_id": "123456782", "document_number": "10001", "total_sum_including_vat": 1170, "total_vat_number": 170, "item_description": "Consulting Service", "item_type": "Service", "sale_currency": "ILS", "sale_vat_rule_vat_exempt": False, "unit_price": 1000, "quantity": 1, "sum_amount_paid_with_this_payment_method": 1170, "payment_methods": "bank_transfer", "origin_tax_deduction": 0, "file_name": "invoice.pdf", "file_path": "uploads/invoices/invoice.pdf", }, ) print(response.text) ``` ### PHP ```php .keep.co.il/partner/api/documents/income/manual'); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Bearer ', ], CURLOPT_POSTFIELDS => $body, ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 201 — Document created (success) | Field | Type | Description | | --- | --- | --- | | `payload` | object | | | `payload.id` | string | Document ID | ### 400 — Bad Request. Returned for validation errors and these refusals: `Bad document number`, `Bad seller identifier`, `There is already document with the same number`, `Could not get file!`, and an error when `osek_type` does not match the seller's record. (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 400, "message": [ "Validation failed" ], "error": "Bad Request" } ``` ### 401 — Unauthorized (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | | | `message` | string | | ```json { "statusCode": 401, "message": "Unauthorized" } ``` - [Get financial checkpoints](https://docs.payme.io/keep/partners-api/getcheckpoints): GET /partner/api/statistic/checkpoints — Get financial checkpoints # Get financial checkpoints - Sandbox: your partner domain on the Keep sandbox: `GET https://.keep.co.il/partner/api/statistic/checkpoints` - Production: your partner domain: `GET https://.keep.co.il/partner/api/statistic/checkpoints` ## Credentials - Header `Authorization: Bearer ` Retrieve financial checkpoints for a seller ## Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `socialId` | query | string | yes | Seller's Israeli ID number: digits only, with a valid check digit. | | `reportingYear` | query | string | yes | Reporting year, 4 digits | | `reportingMonths[]` | query | string | yes | A month as a two-digit string, `01` to `12`. Repeat the parameter once per month, at most 12: `reportingMonths[]=06&reportingMonths[]=08`. Without the brackets (`reportingMonths=06`) the request is rejected with `400`. | ## Code samples ### curl ```bash curl -X GET 'https://.keep.co.il/partner/api/statistic/checkpoints?socialId=&reportingYear=&reportingMonths%5B%5D=' \ -H 'Authorization: Bearer ' ``` ### Node.js ```javascript const response = await fetch("https://.keep.co.il/partner/api/statistic/checkpoints?socialId=&reportingYear=&reportingMonths%5B%5D=", { method: "GET", headers: { "Authorization": "Bearer ", }, }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.get( "https://.keep.co.il/partner/api/statistic/checkpoints?socialId=&reportingYear=&reportingMonths%5B%5D=", headers={ "Authorization": "Bearer ", }, ) print(response.text) ``` ### PHP ```php .keep.co.il/partner/api/statistic/checkpoints?socialId=&reportingYear=&reportingMonths%5B%5D='); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ', ], ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 200 — Successful response (success) | Field | Type | Description | | --- | --- | --- | | `payload` | object | One object for the requested months. The totals are summed over those months. | | `payload.reportingYear` | string | | | `payload.reportingMonths` | array | | | `payload.seller` | object | | | `payload.seller.firstName` | string | | | `payload.seller.lastName` | string | | | `payload.seller.sellerStatus` | integer | Seller status: `-1` new, `0` closed, `1` active. | | `payload.seller.accountEmail` | string | | | `payload.seller.phone` | string | | | `payload.seller.businessNumber` | integer | | | `payload.seller.businessType` | integer | Business type, the same numeric codes as `businessType` in Create seller (`-1` other). | | `payload.seller.industryClassificationId` | integer | | | `payload.seller.idNumber` | integer | | | `payload.seller.socialSecurityAdvAmount` | number | | | `payload.directDebit` | object | Direct debit authorisation per authority, keys `tax-authority`, `vat-authority`, `social-security`. Values: `0` none, `1` started, `2` filled in, `3` authorised. | | `payload.paychecks` | object | Salary figures from the last checkpoint in the period. | | `payload.paychecks.totalIncome` | number | | | `payload.paychecks.totalTax` | number | | | `payload.paychecks.creditPoints` | number | | | `payload.paychecks.marginalTaxRate` | number | | | `payload.totalIncomesWithoutVat` | number | | | `payload.totalIncomesVat` | number | | | `payload.totalIncomesWithVat` | number | | | `payload.totalIncomesDebts` | number | | | `payload.totalIncomesDeposit` | number | | | `payload.totalIncomesOriginTaxDeduction` | number | | | `payload.totalExpensesWithoutVat` | number | | | `payload.totalExpensesWithVat` | number | | | `payload.totalDeductibleExpenses` | number | | | `payload.totalDeductibleExpensesVat` | number | | | `payload.refundPoints` | number | | | `payload.profit` | number | | | `payload.totalIncomesWithoutVatForPeriod` | number | | | `payload.totalIncomesOriginTaxDeductionForPeriod` | number | | | `payload.pendingExpensesTotalWithoutVat` | number | | | `payload.pendingExpensesTotalWithVat` | number | | | `payload.pendingExpensesTotalDeductible` | number | | | `payload.pendingExpensesTotalDeductibleVat` | number | | | `payload.pendingExpensesTotalDeductibleAssetVat` | number | | ### 400 — Bad Request (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 400, "message": [ "Validation failed" ], "error": "Bad Request" } ``` ### 401 — Unauthorized (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | | | `message` | string | | ```json { "statusCode": 401, "message": "Unauthorized" } ``` ### 404 — No seller has this ID number. Message: `Seller not found`. (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | - [Get tax predictions](https://docs.payme.io/keep/partners-api/gettaxpredictions): GET /partner/api/statistic/tax-predictions — Get tax predictions # Get tax predictions - Sandbox: your partner domain on the Keep sandbox: `GET https://.keep.co.il/partner/api/statistic/tax-predictions` - Production: your partner domain: `GET https://.keep.co.il/partner/api/statistic/tax-predictions` ## Credentials - Header `Authorization: Bearer ` Retrieve tax predictions for a seller ## Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `socialId` | query | string | yes | Seller's Israeli ID number: digits only, with a valid check digit. | | `reportingYear` | query | string | yes | Reporting year, 4 digits | | `reportingMonths[]` | query | string | yes | A month as a two-digit string, `01` to `12`. Repeat the parameter once per month, at most 12: `reportingMonths[]=06&reportingMonths[]=08`. Without the brackets (`reportingMonths=06`) the request is rejected with `400`. | ## Code samples ### curl ```bash curl -X GET 'https://.keep.co.il/partner/api/statistic/tax-predictions?socialId=&reportingYear=&reportingMonths%5B%5D=' \ -H 'Authorization: Bearer ' ``` ### Node.js ```javascript const response = await fetch("https://.keep.co.il/partner/api/statistic/tax-predictions?socialId=&reportingYear=&reportingMonths%5B%5D=", { method: "GET", headers: { "Authorization": "Bearer ", }, }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.get( "https://.keep.co.il/partner/api/statistic/tax-predictions?socialId=&reportingYear=&reportingMonths%5B%5D=", headers={ "Authorization": "Bearer ", }, ) print(response.text) ``` ### PHP ```php .keep.co.il/partner/api/statistic/tax-predictions?socialId=&reportingYear=&reportingMonths%5B%5D='); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ', ], ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 200 — Successful response (success) | Field | Type | Description | | --- | --- | --- | | `payload` | object | | | `payload.predictions` | array | | | `payload.predictions[].reportingYear` | string | | | `payload.predictions[].reportingMonth` | string | | | `payload.predictions[].totalIncomesWithoutVat` | number | | | `payload.predictions[].totalIncomesOriginTaxDeduction` | number | | | `payload.predictions[].totalDeductibleExpenses` | number | | | `payload.predictions[].yearlyPredictedProfit` | number | | | `payload.predictions[].predictedTaxAmount` | number | | | `payload.predictions[].paychecksPredictedSalary` | number | | | `payload.predictions[].paychecksPredictedTax` | number | | | `payload.predictions[].refundPointsValue` | number | | | `payload.predictions[].predictedTaxRateADV` | number | | | `payload.reportingYear` | string | | | `payload.reportingMonths` | array | | | `payload.seller` | object | | | `payload.seller.firstName` | string | | | `payload.seller.lastName` | string | | | `payload.seller.sellerStatus` | integer | Seller status: `-1` new, `0` closed, `1` active. | | `payload.seller.accountEmail` | string | | | `payload.seller.phone` | string | | | `payload.seller.businessNumber` | integer | | | `payload.seller.businessType` | integer | Business type, the same numeric codes as `businessType` in Create seller (`-1` other). | | `payload.seller.industryClassificationId` | integer | | | `payload.seller.idNumber` | integer | | | `payload.seller.socialSecurityAdvAmount` | number | | ### 400 — Bad Request (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type | ```json { "statusCode": 400, "message": [ "Validation failed" ], "error": "Bad Request" } ``` ### 401 — Unauthorized (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | | | `message` | string | | ```json { "statusCode": 401, "message": "Unauthorized" } ``` ### 404 — No seller has this ID number. Message: `Seller not found`. (error) | Field | Type | Description | | --- | --- | --- | | `statusCode` | integer | HTTP status code | | `message` | string | Error message(s) | | `error` | string | Error type |