Support · Apps & APIs · 14 min read
An API an operator can run
Document the contract, the errors, and who to call when a webhook fails.

Treat the interface as the product
We treat an API like a product: versioned routes, predictable errors, and a page a future developer can read without calling us. If it only lives in someone’s head, it is not shipped. SYCGeeks has built these contracts from Vancouver since 2015 for stores, mobile apps, and partner tools. The catalog item is a custom API platform, six to twelve weeks, quoted in CAD, with authenticated routes, webhooks, and partner documentation. It is not a pile of scripts a contractor left in a gist.
One written contract beats three undocumented endpoints. “GET /v1/orders/{id}” with a documented 404 and a documented 409 is a product. “Hit the old PHP box and also this Zapier and also Jane’s spreadsheet” is a liability. We decide resources, idempotency, and error shapes up front so mobile, web, and a warehouse do not invent three truths. The contract is a page in your project, not a Slack thread.
Payments, inventory, and appointments are the usual reasons to build one. We connect to Square, Stripe, or your warehouse instead of inventing a fourth system of record. If Square already holds the catalog and the appointments, the API is a disciplined door, not a second shop. Inventing a second shop is how you sell a jacket twice on a Saturday and how refunds vanish.
You do not need a second agency for “the backend.” If we ship the site or the app, we ship the contract, the keys, and the runbook. A specialist firm that only writes APIs and never sits with your operator will miss the Tuesday when the POS is offline. We sit with the operator. Book a Square appointment on Pacific time, or write admin@sycgeeks.ca with the systems you already pay for. No account is required to book.
Versioned routes and a contract you can keep
Version the public surface. /v1/ stays stable when we add /v2/. Breaking a partner because we renamed a field on a Friday is how you earn a second agency — they get paid to soothe the partner. We add fields additively. We deprecate in writing with a date. We do not break a field because a new mobile screen wanted a shorter name. The mobile screen can adapt. The warehouse job that runs at 2 a.m. Pacific cannot.
Idempotency keys on anything that moves money or stock are not optional. A mobile retry, a double-click, a webhook replay — those will happen. If creating an order twice creates two orders, the API is not finished. We document which routes are idempotent and what we return on a replay. Operators should be able to read that sentence. If they cannot, the page is not done.
Pagination, filters, and rate limits belong in the contract. A partner who pulls your entire catalog every five minutes will hurt Square and hurt you. We publish a limit and a 429 they can handle. We do not hide a limit that only appears in production. Staging and production should refuse the same way, with the same error shape, so a partner’s test is meaningful.
REST is the default we can hand to a future WordPress or Next.js developer. GraphQL is a choice when the clients are ours and the query shape is the product. We will not pick GraphQL because it is interesting. If a warehouse needs a nightly CSV and a signed URL, that can be part of the same platform. The contract names the clients: mobile app, marketing site, partner, nightly job. Unnamed clients are how surprise load appears.
Predictable errors a partner can handle
Errors are part of the product. A JSON body with a stable code, a human message, and a request id beats a blank 500. We map the five failures partners actually hit: not found, not allowed, conflict, validation, and upstream timeout. “Card declined” is not the same as “Square did not answer.” The client should branch. So should your support person reading a log on a Monday.
Messages that operators see — in a dashboard, in an app, in an email — must be correct in the language of that surface. A French checkout that surfaces an English API string is a Canadian product bug. We keep a small dictionary for the errors we show humans. Machine-translated API codes are fine as codes. They are not fine as the sentence on a receipt. GST/HST misconfiguration gets its own code. Do not bury tax in “invalid request.”
Validation errors name the field. A partner who sent a US ZIP in a Canadian postal-code slot should hear that, not “bad input.” We accept Canadian postal codes. We do not require a state. Those US leftovers in a schema are how Quebec orders fail. The contract shows the example in CAD, with a Canadian address, because examples get copied.
When our API depends on Square or Stripe and they time out, we fail in a way you can retry. We do not mark an order paid because we hoped. We do not mark it failed if the charge might still settle. That uncertainty is a documented state. Care is how a human looks at those states on a Sunday instead of discovering them in a partner email on Monday. If production is down, call +1 (672) 200-7924 on a weekday. That line is for heat.
Webhooks with retries you can see
Webhooks need retries you can see. A signed payload, a delivery log, and a way to replay from the dashboard are the minimum. “We sent it” is not operations. Partners go down. We go down. Square will retry; so must we. Each delivery attempt gets a timestamp, a status, and the response body we received. If a job moved money and the webhook never landed, an operator should see the red row without opening a terminal.
Verify signatures. Ignore the payload if the secret does not match. Rotate secrets without an outage: two valid secrets for a window, then one. Write the rotation in the project notes. A secret that only lives in a developer’s password manager is how a vacation becomes an incident. We store secrets in the environment we already operate, not in the repository, and we say who can ask for a rotation.
Inbound webhooks from Square or Stripe are how the API learns the truth. Payment completed, appointment cancelled, refund created — those events update your records. Outbound webhooks are how partners learn. Do not make a partner poll every minute for a refund. Push the event. If they cannot accept a webhook, a nightly pull with a cursor is an honest fallback, named in the contract, not a silent extra in week ten.
Replay is a tool, not a weapon. Replaying a paid event must not double-charge. That is the idempotency rule again. We test replay in staging with a CAD amount and a refund. We do not test only with a stub. After launch, the reserved care hour is the right place to replay a stuck delivery. A new event type is a quote. Mixing those two is how care gets abused and how operators stop trusting the log.
Square and Stripe stay the system of record
Your processor is the book for money. Your warehouse or Square catalog is the book for stock. The API is not a third book. We mirror what we must for speed, and we reconcile. If a count disagrees, the processor or the warehouse wins, and we write the incident. A custom table that “is easier to query” becomes the place where Saturday’s sale disappeared. We have cleaned those up. We would rather not build you one.
Choose Square when you sell in a room and online. Appointments, POS, and the site can share one account. Hardware is why people stay. Choose Stripe when subscriptions, usage, or a marketplace live inside a custom Next.js or mobile app. PayPal is a familiar extra, rarely the only rail. We will tell you which integration we can keep healthy after launch, not which logo looks newest. Read Canadian fee pages before you sign. Rates move.
Tax is not a display issue. GST/HST by province, exemptions, shipping to some provinces only — those rules live in the processor or in a tax decision we wrote down. The API should not invent a rate. If the processor returns tax, we pass it through. If we must compute, the rule is in the contract and in the project notes, signed by whoever owns finance. Silent tax logic is how you earn an audit.
Refunds and voids follow the same book. The API exposes them; it does not invent a parallel wallet. If you want a store credit, that is a product decision with a CAD balance and a rule, quoted, not a negative line someone added in a hurry. We test a real CAD refund before launch. A French receipt that is English with accents means we are not done. Currency on every money field is CAD unless the contract says otherwise in writing.
Auth for the clients you actually have
Auth matches the clients. A mobile app you own can use a user token. A partner integration can use a keyed credential with a tight scope: read orders, not refund them. A WordPress site your editor uses should not hold the refund key in a plugin field. We issue the least key that does the job, we name the owner, and we write how to revoke it. Shared “admin” keys in a group chat are an incident waiting for a departure.
Personal information in the API is still personal information. PIPEDA is about purpose. If a partner does not need emails, we do not send emails. If logs contain tokens or card hints, we have already failed. We collect what the route needs and we say why on the privacy page, in both languages if the product is bilingual. Chat and analytics attached to an operator dashboard are in scope too.
WCAG applies to the pages humans use to run the API: the key screen, the delivery log, the replay button. Contrast, labels, keyboard. An operator with a sore hand on a Monday should be able to replay a webhook without a mouse-only table. We do not ship a dark-on-dark admin because it looked like a terminal. Compliance as a deeper punch list is a separate three-to-five-week program if you need it.
Environment separation is boring and mandatory. Keys for staging do not work in production. A partner testing in production is how a real CAD charge appears in a demo. We give you two bases, two secrets, and a sentence in the docs. Next.js or WordPress, the public site uses the public base. Nobody pastes a production secret into a local .env that then gets zipped to email. We will refuse to debug that zip.
A page a future engineer can run without calling us
Documentation is a launch artifact. Resources, example requests in CAD, error codes, webhook topics, and who to call. Screenshots of the dashboard beat adjectives. If a new developer cannot create a test order and replay a webhook from the page, the page is not shipped. We host that page with the project, in English, and in French if partners are French. A PDF dumped at handover will rot.
The runbook is shorter than the contract: how to rotate a key, how to pause a partner, how to read a failed delivery, when to call the studio. Pacific time, weekdays, +1 (672) 200-7924 for heat — checkout down, refunds looping, a flood of 500s. admin@sycgeeks.ca for a brief or a new client. The merchant dashboard holds the notes. “Waiting on warehouse IP allowlist” is a useful note. “Looks good!!” is not.
Status for partners can be a small public page: we are up, we are degraded, webhooks are delayed. You do not need a theatre. You need one URL you can send in an email at 7 a.m. Pacific so five partners do not phone the shop. We can ship that in the platform. A Twitter account is not a status page.
Handoff includes who owns the domain, the hosting, and the processor accounts. We do not leave an API on a personal Square login. If the only person who can see a settlement is a contractor who left, you do not have an API. You have a story. Care at $450 a month or $4,500 a year is how the studio stays on the file: hosting watch, small updates, one reserved hour, a note of what changed. Buy it at checkout or add it later.
Care after launch, and when you do not need an API
After launch, the dangerous part is silent failure. Care means we watch the jobs that move money and write down what we changed. A webhook that stops, a certificate that expires, a Square permission that someone toggled — those are care. A new partner program, a second marketplace, a GraphQL rewrite — those are quotes on the same project. Care members pay about 25 percent less on published add-ons. Eight reserved hours exist when the work is bigger than an hour and smaller than a new platform.
You may not need an API. A marketing site in six to ten weeks, WordPress or Next.js, with a Square booking embed, is enough for many Vancouver firms. A Shopify store with Canadian tax may be enough for a catalog. We will say that. We will not upsell a platform because it is interesting. If a well-made site and the processor’s own tools do the job, that is the recommendation, in writing, before you pay.
You do need an API when a mobile app, a partner, or an internal tool must share one truth with the site. You do need one when checkout is the product — memberships, quotes, unusual tax — and a theme cannot hold it. You do need one when the warehouse must speak every night. Those are the briefs we price at six to twelve weeks, or twelve to twenty when the mobile app is in the same sentence.
Start with the systems you already pay for, the clients who must connect, and the error you are tired of explaining on the phone. Send that to admin@sycgeeks.ca. If a live job is dropping payments today, call. If you want to talk through the contract before you write, book. We quote in CAD against the scope you signed. We open a workflow you can see. Silent calendars are how integrations rot. We will not do that here.
A week-by-week picture for a six-to-twelve-week platform
Week one is the client list and the system of record. We write who reads, who writes, who refunds. We get sandbox access to Square or Stripe and a sample of the warehouse file, even if it is ugly. Week two is the contract page: routes, errors, webhook topics, idempotency. You sign it in the dashboard the way you sign a sitemap. Changing the contract after week two is a change request, not a hallway conversation.
Weeks three to six are the build of v1 and the delivery log. We put a test CAD order through and we refund it. We fail Square on purpose and we read the error. If French surfaces exist, we show the human strings. Weeks seven to ten are partner or mobile hardening, key issuance, and the runbook. Weeks eleven and twelve are the buffer that content and approvals always eat — a finance signer, a warehouse IP, a legal sentence about personal information. If those arrive in week one, you launch nearer six. If they arrive in week ten, you launch nearer twelve, or you pause.
A store or a first app on top of this platform is a second picture, not a free extra. Ecommerce is eight to fourteen weeks. A first mobile app is twelve to twenty. We can sequence them on the same project record so you keep the history. We will not pretend the marketing-site calendar can carry webhooks. The dashboard will name the phase. You will always know whether you are paying for a door, a shop, or a pocket app.
Students who touch the platform log hours with a general description another engineer can read: “Signed Square webhook, added replay button, wrote 409 for duplicate order.” That log is how the studio understands capacity. It is also how you see that work happened. If a week is quiet, ask. If you want the contract walked on a whiteboard before you sign a CAD quote, book time. If money is failing in production tonight, call. Three doors, one studio, no second agency required to keep the door you already bought.



