Quick Notice APIv1.0.0

https://api-staging.sappo.xco.agency

Overview

The Quick Notice API lets you read your own store's Quick Notice data from your own code: a spreadsheet sync, an internal dashboard, a warehouse system, or an AI assistant.

It is a JSON API over HTTPS. Every request is authenticated with a token you create yourself inside the app, and every request only ever sees the store that token belongs to — there is no way to ask for another store's data, and no store id to pass.

  • Base URL — https://api-staging.sappo.xco.agency
  • Shape — GET https://api-staging.sappo.xco.agency/quick-notice/v1/{resource}
  • Authentication — Authorization: Bearer mak_…
  • Machine-readable reference — OpenAPI 3.0 document

Responses are always JSON. A successful resource response carries a data array and a meta object; a failed one carries a single error object and nothing else.

No endpoint changes your data: everything here is a read.

Authentication

Get a token

Open the app in your Shopify admin, go to Settings → API Access, and create a token. The full token is shown once, at creation time; afterwards only its first 12 characters are stored in readable form. If that card is locked, API access is not included in your current plan and the app will not create a token until the plan changes. At most three tokens can be active at once, so revoke one you no longer use before creating another.

A token can be given an optional expiry date, and can be revoked at any time from the same screen. Revoking takes effect on the next request.

Send the token

Put it in the Authorization header of every request, after the word Bearer:

curl "https://api-staging.sappo.xco.agency/quick-notice/v1/notices" \
  -H "Authorization: Bearer mak_your_token_here"

There is no other accepted form: a query-string token, a cookie, or a different header name is rejected with MISSING_TOKEN.

Keep it secret

The token carries everything this API can do with your whole store's data in this app, so treat it like a password:

  • Store it in a server-side secret, not in a browser, a mobile app, or a public repository.
  • Never call this API directly from a storefront page — the token would be visible to every visitor.
  • Create one token per integration, so you can revoke a single one without breaking the others.

A token is stored only as a SHA-256 hash, so nobody — including us — can read it back to you. If you lose it, create a new one and revoke the old.

Making a request

Every resource endpoint is a GET on a resource list:

GET https://api-staging.sappo.xco.agency/quick-notice/v1/{resource}

{resource} is one of the names listed under Resources below. The v1 segment is the API version (see Versioning).

Ask for JSON and read JSON back:

curl "https://api-staging.sappo.xco.agency/quick-notice/v1/notices?page=1&page_size=50" \
  -H "Authorization: Bearer mak_your_token_here" \
  -H "Accept: application/json"

A successful response is always this shape:

{
  "data": [ { "id": 1 } ],
  "meta": { "page": 1, "pageSize": 50, "total": 137 }
}

data holds the records for the page you asked for, in the resource's own field names. meta describes the page.

Each resource's example response below is abridged: a record carries every column stored for it, so expect fields the example does not show. Some resources return customer details, email addresses or codes among them — read the resource's own description before you log, cache or forward a response.

These documentation endpoints need no token at all, so you can explore before you create one:

Endpoint What it returns
GET https://api-staging.sappo.xco.agency/quick-notice/docs This page
GET https://api-staging.sappo.xco.agency/quick-notice/docs.json OpenAPI 3.0 document
GET https://api-staging.sappo.xco.agency/quick-notice/docs/content.json This documentation as JSON
GET https://api-staging.sappo.xco.agency/quick-notice/docs/mcp The MCP guide
GET https://api-staging.sappo.xco.agency/quick-notice/docs/mcp.json The MCP guide as JSON

Pagination

Lists are paged with two query parameters:

Parameter Type Default Notes
page integer 1 1-based. Anything below 1 is treated as 1.
page_size integer 25 Capped at 100. A larger value is silently reduced to 100.

Note the asymmetry: the request parameter is page_size (snake case), while the field echoed back in meta is pageSize (camel case).

"meta": { "page": 2, "pageSize": 25, "total": 137 }

total is the number of records matching your filters, not the number on this page. Walk the list until page * pageSize >= total:

# 137 records at 25 per page = 6 pages
for page in 1 2 3 4 5 6; do
  curl -s "https://api-staging.sappo.xco.agency/quick-notice/v1/notices?page=$page&page_size=25" \
    -H "Authorization: Bearer mak_your_token_here"
done

Records are returned newest first. Which timestamp "newest" means depends on the resource — creation time for most, last-change or scheduled time for a few — and each resource's description below says which. Because new records can arrive while you page, a long walk can show a record twice or skip one; if that matters, page from the last page backwards, or filter to a window that has stopped changing.

Filtering

Any query parameter other than page and page_size is passed to the resource as a filter. Each resource accepts its own set — the supported names, types and allowed values are listed per resource under Resources below, and in the OpenAPI document.

# Only the records a resource's own `status` filter matches
curl "https://api-staging.sappo.xco.agency/quick-notice/v1/notices?status=PENDING" \
  -H "Authorization: Bearer mak_your_token_here"

Three things to know:

  • An unknown filter is ignored, not rejected. A misspelled parameter returns the unfiltered list with 200, so check your spelling against the resource's parameter list if a result looks too large.
  • Filters combine with AND. Passing two filters narrows the list to records matching both.
  • Booleans accept the usual spellings — true, 1, yes, on are true; anything else is false.

Filters apply before paging, so meta.total reflects the filtered count.

Errors

Every failure of a resource endpoint returns the same envelope, with the HTTP status repeated inside the body so it survives logging:

{
  "error": {
    "code": "INVALID_TOKEN",
    "message": "Token is invalid, expired, or revoked.",
    "status": 401
  }
}

Branch on error.code, never on error.message — the wording may be improved, and we aim to keep the codes stable within a version. The table under this section lists every code a resource endpoint can return, and what to do about each.

Two cases are worth calling out because they look like one another:

  • MISSING_TOKEN means the Authorization header was absent or did not begin with Bearer . Your request never reached a token lookup.
  • INVALID_TOKEN means a token was sent but did not pass: it does not exist, it was revoked, it expired, or the store is suspended. The API deliberately does not tell you which, so a token cannot be probed.

Rate limits

Each token may make 60 requests per 60 seconds. The budget is per token, not per IP address, so splitting work across machines does not raise it — creating a second token for a second integration does.

Every successful response carries your current standing:

Header Meaning
X-RateLimit-Limit Requests allowed per window (60).
X-RateLimit-Remaining Requests left in the current window.
X-RateLimit-Reset Unix timestamp one full window after this request. On a 429 it is when you may retry.

Over the limit you get 429 with error.code of RATE_LIMITED, plus a Retry-After header holding the number of seconds to wait. The 429 response repeats X-RateLimit-Limit, X-RateLimit-Remaining (always 0) and X-RateLimit-Reset.

Honour Retry-After rather than retrying immediately:

response=$(curl -s -D headers.txt "https://api-staging.sappo.xco.agency/quick-notice/v1/notices" \
  -H "Authorization: Bearer mak_your_token_here")
# on 429: sleep "$(grep -i '^retry-after:' headers.txt | tr -dc '0-9')"

For a large export, prefer a bigger page_size over more requests: one request for 100 records costs the same budget as one request for a single record.

The documentation endpoints are not metered by this budget.

Versioning

The version is the v1 segment in the path, and this documentation describes release 1.0.0.

Inside v1 we aim to make only additive changes: a new resource, a new filter, or a new field on a record. Treat unknown fields as something to ignore rather than something to fail on, and your integration will keep working.

A change that could break a reader — a field removed or renamed, a filter's meaning changed, a status value dropped — belongs on a new path segment (v2), with v1 still answering. Bug fixes are the exception we do make inside v1: where a list was ordered by the wrong column, correcting it changes what page one returns.

info.version in the OpenAPI document is the documentation release; the path segment is the API contract. Pin the path segment in your code, and re-read the document when info.version changes.

MCP for AI assistants

The Model Context Protocol (MCP) is an open standard that lets an AI assistant call tools on a server instead of guessing from text: you connect the assistant once, it discovers which tools exist, and then it can answer "how many claims are still pending?" by actually querying your store rather than inventing a number. Claude Desktop, Claude Code and a growing list of other clients speak it.

Quick Notice exposes the same data as this API over MCP at https://api-staging.sappo.xco.agency/quick-notice/mcp, authenticated with the same mak_ token in the same Authorization header. No separate signup, no second credential.

The tool list, the exact client configuration to paste, and the errors to expect are on the MCP guide, with a machine-readable copy at https://api-staging.sappo.xco.agency/quick-notice/docs/mcp.json.

Error reference

StatusCodeMessageWhat to do
400 INVALID_PAGE Query parameter page must be a positive integer.

Send page as a whole number of 1 or more, or leave it out for the first page. A page past the end is not an error: it answers 200 with an empty data array.

400 INVALID_PAGE_SIZE Query parameter page_size must be an integer between 1 and 100.

Send page_size as a whole number between 1 and 100. Leave it out for the default of 25. Asking for more than the maximum is refused rather than quietly reduced, so a client cannot believe it received a bigger page than it did.

401 MISSING_TOKEN Authorization header with Bearer token is required.

Send an Authorization: Bearer mak_… header. This code also appears when the header is present but does not start with Bearer — a bare token or a Token … prefix is not accepted.

401 INVALID_TOKEN Token is invalid, expired, or revoked.

Check the token was copied in full, is still listed as active in Settings → API Access, and has not passed its expiry date. Create a new token if in doubt. The same code is returned when the store is suspended.

403 PLAN_REQUIRED API access is not included in the current plan.

The token is valid, but this app sells API access on named plans only and this store is not on one of them. The plans that carry it are listed under Authentication above; change the plan in the app and the same token starts working — there is no need to create a new one.

403 INSUFFICIENT_SCOPE This token does not include the {resource}:read scope.

The token is valid and the plan allows the API, but this token was created without the scope for that resource. Scopes are fixed when a token is created, so create a new one that includes it — a token minted before scopes existed carries the wildcard and is unaffected.

404 APP_NOT_FOUND App not found.

The app handle in the path is not one Sappo serves. Use the handle this documentation was generated for, and check for a typo or a stray path segment.

404 RESOURCE_NOT_FOUND Resource '{resource}' is not available for 'quick-notice'.

The app is valid but it does not expose that resource. Use one of the resource names listed in this documentation, or read them from https://api-staging.sappo.xco.agency/quick-notice/docs.json.

404 NOT_FOUND No record found for id {id}.

The resource exists but holds no record with that id for your store. Check the id came from this app and this store — ids are not shared between apps. This is the single-record form; a list request with no matches answers 200 with an empty data array instead.

429 RATE_LIMITED Too many requests. Please slow down.

Wait the number of seconds in the Retry-After header before retrying, and keep each client under 60 requests per 60 seconds. Fetch more records per request instead of making more requests.

500 INTERNAL_ERROR An internal error occurred.

The request was accepted but failed on our side; it has been reported to us automatically. Retry once after a short pause, and if it persists contact support with the time of the request and the path you called.

503 API_NOT_AVAILABLE The API is not available for this app yet.

The app is served but its store of API tokens has not been created yet, so no token can be checked. Nothing is wrong with your request: retry later, and tell support if it lasts.

Endpoint reference