Build against facts.
A small REST interface for external purchasing agents. Public reading, private quoting, explicit limits.
Authentication
Catalog, products, recommendations and policies are public. Quotes need an operator-issued bearer key. Ask Safi.pk support for access. Quote ownership is bound to the key’s principal, not its ID. Keys can be rotated while keeping the principal. Reviewer keys only read the local review queue; no approvals or notifications are sent.
Authorization: Bearer YOUR_ISSUED_KEY
Content-Type: application/json
Idempotency-Key: unique-request-0001Never put keys in URLs. Keep customer data out of requests. No card details are accepted.
Resources
| Method | Path | Access |
|---|---|---|
| GET | /api/v1/catalog | Public |
| GET | /api/v1/products/{id} | Public |
| GET | /api/v1/policies | Public |
| GET | /api/v1/recommendations?sites=2&storage_gb=20&managed=false | Public |
| POST | /api/v1/quotes | Agent |
| GET | /api/v1/quotes/{id} | Owner |
| POST | /api/v1/quotes/{id}/counteroffers | Owner |
| POST | /api/v1/quotes/{id}/accept | Owner |
| POST | /api/v1/quotes/{id}/reject | Owner |
| GET | /api/v1/reviews | Reviewer |
A hosting request
{
"currency": "PKR",
"lines": [
{
"product_id": "hosting-298",
"offer_id": "annual",
"quantity": 1
}
]
}Counteroffer: {"requested_discount_bps":500}. With no approved discount policy, it enters pending_review and the calculated price stays unchanged. Limit: 3 rounds; identical repeats are rejected.
Accept: send the current revision and acknowledge_live_check:true. All hosting and domain checkout is disabled. Acceptance requests return checkout_disabled/409; quotes remain in manual review. Catalog changes require a new quote and renewed acceptance.
Limits & errors
16 KiB JSON bodies · 5 lines · quantity 1–10 · 24-hour expiry · 30 authenticated requests/minute/principal · 120 public requests/minute/IP · 1,000 quotes/principal.
400 invalid_input · 401 unauthorized · 403 forbidden · 404 not_found · 409 review_required / catalog_changed / round_limit / idempotency_conflict · 410 quote_expired · 413 request_too_large · 415 unsupported_media_type · 429 rate_limit · 503 unavailable.
Retries must use the same Idempotency-Key and body. Keys are scoped to a principal across all mutations. A retry returns the quote’s current state. Unknown fields are rejected. External text cannot alter policy, request a URL fetch or select a checkout destination.
A2A
A2A 1.0 JSON-RPC is implemented through the official SDK. Read /developers/a2a for the structured message profile, task semantics and limitations. No platform-specific endorsement is claimed.
Official specification ↗