No internet connection.
Issuing, saving and searching will not work until it is back.
REST API · v1
Narra Warranty API
Issue warranties from your POS or inventory system, and read them back. What comes
out is the document your counter issues: sealed at the moment it is made, sent to
the customer, and verifiable by anyone holding the link.
The API is organised around REST: predictable URLs, JSON bodies, standard verbs and
conventional status codes. Every request is made over HTTPS and carries an API key.
Everything it can do, a person can do in the app. It is a second door into the same
rooms and never a shortcut past a rule: issuing goes through the same code the
counter uses, so a warranty type's required serial, its period and its terms apply
exactly as they do to a staff member standing at a till.
The API is on the Shop+ plan. Keys are made in the app
under My account → API keys, and the plan is checked on every request rather
than when the key was made.
Quickstart
Three calls: find a warranty type, issue against it, read it back.
Create a key in the app under My account → API keys → New key.
It is shown once, so copy it then; if it is lost, revoke it and make another. A key is
the whole shop's access and does not expire, so keep it on your server and never in a
browser, a mobile app or a repository.
Send it as a bearer token on every request. There is no cookie and no session.
{
"error": {
"code": "bad_key",
"message": "That key is not valid."
}
}
Wrong, revoked and never-existed all answer the same way. Telling them apart would
tell somebody holding a stolen key which one they were holding.
Requests & responses
Bodies are JSON and want Content-Type: application/json. A body over 1 MB is refused.
Unknown fields are rejected, not ignored. A typo in a field name comes back as bad_json rather than silently doing nothing.
Dates are YYYY-MM-DD in Manila time. issued_at is RFC 3339 in UTC.
Money is in pesos, as a number: 32500 or 32500.50.
A reference may be written with or without its dash, in any case: MZ7X-X1JQ and mz7xx1jq reach the same warranty.
Errors
Every failure takes one shape, so you can branch on code instead of reading prose.
RESPONSE
{
"error": {
"code": "rejected",
"message": "Customer name is required."
}
}
Status
Code
Means
400
bad_json
The body did not read as the documented JSON, or named a field that does not exist
401
no_key
No Authorization header
401
bad_key
Wrong, revoked, or never existed
402
plan_required
The shop is not on Shop+
404
not_found
No warranty here with that reference
422
rejected
The warranty was refused; the message says what to fix
500
server_error
A fault here. Nothing was issued
Limits
No rate limit today. There is no request ceiling and no 429. If one is ever needed it will be announced before it is switched on.
No idempotency key yet. A call that times out may still have issued the warranty. Look it up by reference or serial before sending it again.
limit on the list endpoint defaults to 50 and caps at 200.
A plan that lapses stops the key. The shop keeps everything it issued, but calls
answer plan_required until it is back on Shop+.
Warranty types
A warranty type carries the terms, the period and what a warranty of that kind must
record. Issuing needs one, and its id is not guessable, so this is the call to make
first. Types are set up by the shop in the app and their ids are stable.
needs_serial and needs_amount are the type's own rules. Issue
without what they ask for and the call comes back rejected.
Warranties
A warranty is signed when it is created and can never be edited afterwards: that
is the whole point of it. Validate before you post; a mistake means voiding it in the
app and issuing another.
Endpoints
POST/api/v1/warranties
Issue a warranty. Returns 201 with the customer's link.
The customer's copy. Print it on a receipt or send it yourself
verify
Where anyone can check the warranty against the shop's record
fingerprint
The seal, in three groups. Present once the warranty is sealed
status
Where the warranty stands today, computed rather than stored
purchased_on, expires_on
Calendar dates, Manila
issued_at
When it was created. RFC 3339, UTC
status is one of
activeexpiringexpiredusedvoided
A warranty type's category is one of
productservice
expiring means inside its last 30 days, and used means the
claims it allowed are spent. Both are worked out when you ask, so a warranty read
twice a month apart can answer differently without anything having changed.
Before you build
A warranty cannot be edited. It is signed at issue and any change
would break the seal that makes it worth having.
Voiding is not exposed. It cannot be undone and asks for a reason the
customer reads, so it stays a decision a person makes in the app.
Nobody is recorded as the issuer. A warranty made here belongs to the
shop; the counter records the staff member who was standing there, and there was
nobody standing here.
The email is ours to send. Leave send_email alone and the
customer gets the warranty from the shop's name, with your reply-to. Set it false and
delivery is entirely yours.
No webhooks yet. Nothing is sent to you when a claim is recorded or a
warranty expires. Ask if you need it: it is a small thing to add for a real use.