Salami Gateway

API Documentation
Back to Dashboard

Authentication

Salami Gateway uses Laravel Sanctum token-based authentication. Every API request (except provider callbacks and webhooks) must include a valid Bearer token in the Authorization header.


How it works

  1. You create a Personal Access Token from the dashboard or via the web endpoint.
  2. Sanctum returns a plain-text token in the format {id}|{random-string}.
  3. You include that token in every API request.
  4. Salami verifies the token, checks its scopes against the requested endpoint, and either processes the request or returns 401/403.
Authorization: Bearer 1|a8Bk3xY9zR4mNpQ7wXcV2bLsKjHgFdE...

Tokens are hashed before storage. The plain-text value is shown exactly once at creation time. If you lose it, revoke the old token and create a new one.


Creating tokens

Via the dashboard (recommended)

  1. Go to Account > API Tokens > Add New Token.
  2. Fill in:
    • Name -- a human-readable label (e.g. production-erp, staging-mobile-app).
    • Scopes -- the permissions this token should have (comma-separated or selected via checkboxes).
    • Expires at -- optional expiry date. Leave blank for a non-expiring token.
  3. Click Save.
  4. Copy the token from the confirmation dialog. It will not be shown again.

Via the web endpoint

curl -X POST https://yourtenant.salami.dgl.co.ke/account/api_tokens \
  -H "Content-Type: application/json" \
  -H "Cookie: <your-session-cookie>" \
  -H "X-CSRF-TOKEN: <csrf-token>" \
  -d '{
    "name": "my-server-token",
    "abilities": "payments:read,payments:write,sms:write",
    "expires_at": "2027-06-01"
  }'

Response (success):

{
  "success": true,
  "token": "3|xK9mR4a8Bk3...plainTextToken",
  "msg": "API token created successfully"
}

Parameters:

Parameter Type Required Description
name string Yes Unique name for this token
abilities string No Comma-separated list of scopes. Defaults to * (full access)
expires_at date No ISO 8601 date (YYYY-MM-DD). Must be in the future. Null = never expires

Token scopes

Scopes restrict what a token can do. Each scope maps to a set of API routes. A request to an endpoint that falls outside the token's scopes returns 403 Forbidden.

Individual scopes

There are 17 scopes across four modules:

Payments (3 scopes)

Scope Description Endpoints granted
payments:read View payment apps, transactions, balances, and statuses GET /api/pay/apps, GET /api/pay/{app}/transaction/{id}, GET /api/pay/{app}/queryTransactions, GET /api/pay/{app}/checkBalance, GET /api/pay/{app}/fetchTransactions, GET /api/pay/{app}/getTransactionStatus/{txn}, GET /api/pay/{app}/checkPaymentRequestStatus/{txn}, GET /api/pay/{app}/getInstructions/{txn}
payments:write Create and modify transactions POST /api/pay/{app}/extractTransaction, POST /api/pay/{app}/registerUrls, POST /api/pay/{app}/requestPayment, POST /api/pay/{app}/reverseTransaction/{txn}, POST /api/pay/{app}/sendAirtime, POST /api/pay/{app}/sendMoney, POST /api/pay/{app}/simulateTransaction, ANY /api/pay/{app}/validateTransaction
payments:callback Handle payment provider callbacks ANY /api/pay/{app}/callback/{action?}

SMS (4 scopes)

Scope Description Endpoints granted
sms:read View SMS apps, messages, inbox, outbox, and call logs GET /api/sms/apps/{app}, POST /api/sms/groups/{app}, GET /api/sms/apps/{app}/inbox, GET /api/sms/apps/{app}/outbox, GET /api/sms/apps/{app}/calls, GET /api/sms/sms/{id}
sms:write Send SMS messages to individuals and groups POST /api/sms/apps/{app}/send, POST /api/sms/groups/{app}/send
sms:sync Synchronise SMS data from Android gateway apps ANY /api/sms/msync, ANY /api/sms/smssync
sms:receive Receive incoming SMS messages and delivery callbacks ANY /api/sms/apps/{app}/receive, ANY /api/sms/apps/{app}/callback

eTIMS OSCU (3 scopes)

Scope Description Endpoints granted
etims:read View device info, sales, purchases, stock, items, code tables, notices, reports, customers, suppliers, credit notes, reverse invoices, verifications, and business info 27 read-only eTIMS endpoints
etims:write Submit sales, purchases, stock movements, items, customers, suppliers, credit notes, and reverse invoices; initialize device; acknowledge notices 16 write eTIMS endpoints
etims:callback Handle eTIMS/KRA webhook callbacks ANY /api/kra/etims/webhook/callback

KRA Portal (6 scopes)

Scope Description Endpoints granted
kra:apps List and test KRA app configurations GET /api/kra/apps, POST /api/kra/apps/{id}/test
kra:checkers PIN validation, TCC checks, invoice lookup, customs declarations, exemptions, tax service office 13 checker endpoints under /api/kra/checkers/...
kra:payments Generate Payment Reference Numbers for withholding taxes (IT, rental, VAT) POST /api/kra/payments/it-withholding, POST /api/kra/payments/rental-withholding, POST /api/kra/payments/vat-withholding
kra:compliance Apply for Tax Compliance Certificates POST /api/kra/compliance/tcc-application
kra:registration Register new KRA PINs POST /api/kra/registration/pin
kra:returns File TOT and NIL tax returns POST /api/kra/returns/tot, POST /api/kra/returns/nil

Wildcard

Scope Description
* Full access to every endpoint. Use only for admin or internal tooling.

Scope groups

Scope groups are pre-defined bundles for common use cases. Select a group in the dashboard to automatically check all its member scopes.

Group key Label Included scopes
payments_full Full Payments Access payments:read, payments:write, payments:callback
sms_full Full SMS Access sms:read, sms:write, sms:sync, sms:receive
etims_full Full eTIMS Access etims:read, etims:write, etims:callback
kra_full Full KRA Portal Access kra:apps, kra:checkers, kra:payments, kra:compliance, kra:registration, kra:returns
kra_read_only KRA Read Only kra:apps, kra:checkers
read_only Read Only (all modules) payments:read, sms:read, etims:read, kra:apps, kra:checkers
send_only Send Only payments:write, sms:write
full_access Complete Full Access All 16 non-wildcard scopes

Choosing the right scopes -- principle of least privilege

Grant only what the token needs. Examples:

Use case Recommended scopes
Reporting dashboard payments:read, sms:read, etims:read
Payment collection server payments:read, payments:write, payments:callback
SMS marketing campaign sms:write
POS system with eTIMS etims:read, etims:write
KRA compliance tool kra:checkers, kra:compliance
ERP full integration full_access group

Per-request app selection (KRA module)

KRA Portal endpoints require you to specify which KRA app to use on every request. This is because a single account can have multiple KRA apps for different taxpayer PINs or environments.

Pass the app ID using either method:

Option A -- HTTP header (recommended)

curl -X POST https://yourtenant.salami.dgl.co.ke/api/kra/checkers/pin \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "X-KRA-App-Id: 3" \
  -H "Content-Type: application/json" \
  -d '{"KRAPIN": "P051234567A"}'

Option B -- request parameter

curl -X POST https://yourtenant.salami.dgl.co.ke/api/kra/checkers/pin \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "kra_app_id": 3,
    "KRAPIN": "P051234567A"
  }'

If neither is provided, the API returns:

{
  "success": false,
  "error": "kra_app_id is required. Pass it as a parameter or X-KRA-App-Id header."
}

Payments and SMS modules use path-based app selection instead (/api/pay/{payment_app}/... and /api/sms/apps/{sms_app}/...), so no extra header is needed.


Token expiry and revocation

Expiry

Revocation

Revoke a token instantly from the dashboard or programmatically:

curl -X POST https://yourtenant.salami.dgl.co.ke/account/api_tokens/5/revoke \
  -H "Cookie: <your-session-cookie>" \
  -H "X-CSRF-TOKEN: <csrf-token>"
{
  "success": true,
  "msg": "API token revoked successfully"
}

Revoked tokens return 401 on all subsequent requests.

Deletion

Deleting a token permanently removes it:

curl -X DELETE https://yourtenant.salami.dgl.co.ke/account/api_tokens/5 \
  -H "Cookie: <your-session-cookie>" \
  -H "X-CSRF-TOKEN: <csrf-token>"

Example requests with authentication

Minimal headers

Every authenticated request needs at minimum:

curl https://yourtenant.salami.dgl.co.ke/api/pay/apps \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json"

POST with JSON body

curl -X POST https://yourtenant.salami.dgl.co.ke/api/pay/1/requestPayment \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "phone": "254712345678",
    "amount": 500,
    "reference": "ORDER-12345",
    "description": "Payment for order #12345"
  }'

KRA request with app header

curl -X POST https://yourtenant.salami.dgl.co.ke/api/kra/payments/it-withholding \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-KRA-App-Id: 2" \
  -d '{
    "transactionHeader": {
      "withholderPin": "P051234567A",
      "transactionUniqueNo": "WHT-2026-001",
      "noOfTransactions": 1,
      "taxPeriodFrom": "01/03/2026",
      "taxPeriodTo": "31/03/2026",
      "totalGrossAmount": 100000,
      "totalTaxAmount": 5000
    },
    "transactionDetails": [
      {
        "payeePin": "P059876543B",
        "grossAmount": 100000,
        "taxAmount": 5000
      }
    ]
  }'

Security best practices

  1. Never expose tokens in client-side code, URLs, or version control.
  2. Store tokens in environment variables or a secrets manager (e.g. AWS Secrets Manager, HashiCorp Vault).
  3. Rotate tokens regularly -- every 90 days is a good baseline.
  4. Use separate tokens for development, staging, and production.
  5. Revoke compromised tokens immediately from the dashboard.
  6. Use the narrowest scopes possible -- a token that only needs to send SMS should not have payment permissions.
  7. Always use HTTPS -- Salami rejects plain HTTP requests in production.
  8. Monitor token usage -- the token detail page in the dashboard shows request counts, error rates, and average latency.

Troubleshooting

Symptom Cause Fix
401 Unauthorized Missing, malformed, expired, or revoked token Check the Authorization header format. Create a new token if the old one is expired or revoked.
403 Forbidden Token lacks the required scope Check which scope the endpoint needs (see tables above) and create a token with that scope.
422 kra_app_id is required KRA endpoint called without specifying an app Add the X-KRA-App-Id header or kra_app_id body parameter.
Token not accepted after creation Token string was truncated or had whitespace added during copy/paste Ensure the full token (including the numeric prefix and pipe character) is used exactly as shown at creation time.

Back to documentation home


Need help? Contact us at support@dgl.co.ke
© 2026 Deadan Group Limited. All rights reserved.
⚡ API Explorer
LIVE
// Response will appear here...