← the whole book on one page

Chapter 9: APIs as Products — Designing, Governing, and Supporting the Interfaces Others Build On

The endpoints tell a partner what it can build. The terms tell it whether building was wise.

Chapter 8 dealt with software we cannot recall: an app on a fan’s phone keeps calling our backend long after we have shipped something better. An application programming interface (API) puts us in the same position at one remove, because there the code we cannot recall belongs to someone else. A partner builds its product against our contract and plans its year around it, and from then on every change we make lands in a business we do not run. The Architecture book’s Chapter 7 settled how Encore’s public API at api.encore.com is shaped, evolved, secured and governed. This chapter asks a product question about the same interface. What does it take for an API to be something other companies choose to build on, and go on building on, year after year? The sections that follow answer in turn: design from the consumer’s job outward, adopt patterns once, keep 40 teams consistent without a review board, run the partner API as a product with its terms, and run the webhooks that tell partners what happened.

The terms deserve particular attention, and the clearest lesson in why comes from Twitter. Twitter launched in July 2006 and opened its API early, and for several years it let outside developers invent much of what people came to think of as Twitter. The Iconfactory’s Twitterrific, released for the Mac in January 2007, was among the first third-party clients; it gave Twitter its first bird icon and was the app that popularized the word “tweet”. Other clients followed, and Twitter began to buy them: Tweetie in 2010, which became the official iPhone app, and TweetDeck in May 2011, reportedly for about $40 million.

The turn came in stages. On 11 March 2011 Ryan Sarver, Twitter’s head of platform, told developers on Twitter’s developer mailing list that they should not “build client apps that mimic or reproduce the mainstream Twitter consumer client experience”. On 16 August 2012 Twitter’s Michael Sippey published “Changes coming in Version 1.1 of the Twitter API”. Part of it was ordinary engineering: authentication on every endpoint, and limits per endpoint, 60 calls an hour for most and 720 for a few, in place of a flat 350. The rest changed the Developer Rules of the Road. Display guidelines became Display Requirements, backed by “we reserve the right to revoke your application key”. Client apps pre-installed on devices would need Twitter’s certification. And any app that used the home timeline, account settings, direct messages or User Streams “will need our permission if your application will require more than 100,000 individual user tokens”. Apps already past that line could grow to 200% of their token count as of that day and then add no more users without permission.

Notice what did not change in 2012. Every endpoint kept working. What changed was who could call them, how many people an app could serve and how a tweet had to look on screen, and those rules lived in a policy document. They reached far into other companies’ businesses. When Tapbots shipped Tweetbot for Mac on 18 October 2012, it priced the app at $19.99, because its allotment of user tokens was fixed and Twitter would not raise it; a clause in one company’s API policy had set the retail price of another company’s product. Still, the 2012 changes came with notice. They were announced weeks ahead, existing apps kept room to grow, and the old API’s retirement was extended twice. The second act had no notice at all. Elon Musk’s ownership of Twitter began in late October 2022, and around 12 and 13 January 2023 Tweetbot, Twitterrific, Echofon and other clients simply stopped working. On 17 January @TwitterDev said that “Twitter is enforcing its long-standing API rules”. Two days later the Developer Agreement gained a clause against using Twitter’s content to “create or attempt to create a substitute or similar service or product to the Twitter Applications”, and the Iconfactory discontinued Twitterrific after 16 years, describing “an unannounced and undocumented policy change by an increasingly capricious Twitter”. Figure 9.1 sets the dates of both acts side by side.

Twitter's clients, 2006–2023 A schematic timeline in three columns. Courtship, then a warning, 2006 to 2011: Twitter launches in July 2006 with an API open early; the Iconfactory's Twitterrific for Mac arrives in January 2007, giving Twitter its first bird icon and popularizing the word tweet; Twitter buys Tweetie in 2010, which becomes its official iPhone app; on 11 March 2011 Ryan Sarver tells developers not to build client apps that mimic or reproduce the mainstream Twitter consumer client experience; in May 2011 Twitter buys TweetDeck, reportedly for about 40 million dollars. The rules, with notice, 2012 to 2013, highlighted: on 16 August 2012 Michael Sippey announces API version 1.1 and new Developer Rules of the Road: authentication on every endpoint, 60 calls an hour per endpoint (720 for a few) in place of a flat 350, Display Requirements, certification for pre-installed client apps, and Twitter's permission above 100,000 user tokens, with apps already past that line allowed to grow to 200 percent of their count; version 1.1 ships on 5 September 2012 with six months promised to migrate; Tweetbot for Mac ships on 18 October 2012 at 19.99 dollars because its token allotment is fixed; in March 2013 version 1.0's retirement moves to 7 May with blackout tests; on 11 June 2013 version 1.0 returns 410 Gone. Every endpoint kept working. The cut-off, without notice, 2022 to 2023, highlighted: Elon Musk's ownership begins in late October 2022; around 12 and 13 January 2023 Tweetbot, Twitterrific, Echofon and other clients stop working with no notice; on 17 January @TwitterDev says Twitter is enforcing its long-standing API rules; on 19 January the Developer Agreement bars building a substitute or similar service or product, and the Iconfactory ends Twitterrific after 16 years. The written rule came a week after the act. COURTSHIP, THEN A WARNING · 2006–2011 THE RULES, WITH NOTICE · 2012–2013 THE CUT-OFF, WITHOUT NOTICE · 2022–2023 EVERY ENDPOINT KEPT WORKING THE WRITTEN RULE CAME A WEEK LATER TWITTER AND ITS THIRD-PARTY CLIENTS · SCHEMATIC TIMELINE, NOT TO SCALE Jul 2006 Twitter launches; its API is open early Jan 2007 Iconfactory's Twitterrific for Mac: first bird icon; the app that popularized "tweet" 2010 Twitter buys Tweetie; it becomes the official iPhone app 11 Mar 2011 Ryan Sarver: do not "build client apps that mimic or reproduce the mainstream Twitter consumer client experience" May 2011 Twitter buys TweetDeck, reportedly for about $40 million 16 Aug 2012 Sippey announces API v1.1 and new Rules of the Road: auth everywhere; 60 calls an hour (720 for a few), not a flat 350; Display Requirements; certification for pre-installed apps; permission above 100,000 user tokens; apps past it may grow to 200% 5 Sep 2012 v1.1 ships, with six months promised to migrate 18 Oct 2012 Tweetbot for Mac ships at $19.99: its token allotment is fixed Mar 2013 v1.0's retirement moved to 7 May, with blackout tests before it 11 Jun 2013 v1.0 returns 410 Gone Late Oct 2022 Elon Musk's ownership of Twitter begins 12–13 Jan 2023 Tweetbot, Twitterrific, Echofon and other clients stop working, with no notice 17 Jan 2023 @TwitterDev: "Twitter is enforcing its long-standing API rules" 19 Jan 2023 Developer Agreement bars a "substitute or similar service or product"; Iconfactory ends Twitterrific after 16 years Dated event A turn in the terms partners lived by

Figure 9.1 — Twitter and its third-party clients, 2006–2023. Every endpoint survived both turns; what differed was notice, which came weeks ahead and with room to grow in 2012, and not at all in 2023.

The strategic question of how far a company should open its platform belongs to Chapter 2 and to the Software book’s Section 8.1. This chapter takes from Twitter one narrower lesson, about contracts: what a partner depends on includes the terms around the endpoints, and what most decides whether a partner can live with those terms is notice. Since its sixth year Encore has run Partner Listings, a one-way arrangement in which authorized partners read Encore’s event listings and post links to resale offers held on their own sites. Verified Resale turns that into a two-way product. Partners will read each organizer’s resale rules, list tickets that fans bought through the Sale Gate, receive orders when another screened fan buys, and learn the result of the reissue that gives the buyer a new barcode. Rowmate is the launch partner, and Tessera follows. The Partner APIs team owns this surface over the Resale service, and the chapter follows it from its first job story to a certified partner and the listing.sold webhook.

9.1 Designing from the Outside In

Job stories to capabilities

Most APIs are designed from the inside out. A team has a service, the service has tables, and the API appears as a set of doors into those tables. The Architecture book’s Section 7.1 warned against exporting the schema, but a warning tells us what to avoid without telling us where to begin. Designing from the outside in begins with the consumer’s situation and works inward until it reaches the resources and verbs, so that the shape of the API is decided by the work it supports.

The most useful starting form is the job story: a requirement written from the consumer’s situation, in the form “When [situation], I want to [motivation], so I can [outcome]”. Alan Klement described the format in 2013 and credited it to the product team at Intercom. Section 2.2 taught jobs to be done, and we will not teach it again here. The step this chapter adds is the move from a job to an API. James Higginbotham’s Principles of Web API Design (2021) calls the thing in between a digital capability: something the API lets a consumer accomplish, named in the consumer’s words, before any resource, path or verb has been chosen. His process has four phases, which he calls ADDR: Align, Define, Design and Refine. Job stories and capabilities are the alignment phase, the point at which the API is tied to the discovery work of Chapter 3.

Rowmate’s first job story came straight out of the discovery interviews. “When a fan lists a ticket on our site, I want to know at once whether the organizer allows it, so the listing never fails later.” Everything that matters in that sentence is about timing and failure. The capability it yields is “check whether a ticket may be listed, and at what price”, and it says nothing yet about endpoints. A second story, from the same interviews, was “When a listing sells, I want to know before the buyer leaves our checkout page, so I can show them their ticket is on its way”. Its capability is “learn that a sale completed and what happened to the ticket”. Holding capabilities in the consumer’s words for a while keeps the team from reaching too early for the nouns it already owns.

The touring world has an old instrument for this. A touring act sends every venue a technical rider listing what the show needs: power, rigging points, stage size, hands at load-in. The venue that reads the rider before the trucks arrive builds what the show needs, and the one that does not finds out at four in the afternoon. Job stories are an API’s rider, written from the consumer’s side. The analogy breaks on the number of authors. A venue reads one rider from one act it has booked. An API serves many consumers, most of whom never write anything down, so the provider has to write the riders on their behalf and then check its drafts with real consumers. Job stories are widely used but have no outcome studies behind them; their value here is that they make the consumer’s situation the first thing written down and tie the API to the discovery evidence that justified it.

Walking the paths

A capability is a goal; an API needs operations. The bridge between them is to walk the consumer’s journey step by step and ask, at each step, what the consumer needs from us. Arnaud Lauret’s The Design of Web APIs (second edition, 2025) gives this a one-page tool, the API Capabilities Canvas, on which a team writes the journey’s steps, the actors, the inputs and outputs and the operations that fall out. The canvas is one author’s method. The practice beneath it is much older. Alistair Cockburn’s Writing Effective Use Cases (2000) taught a generation of analysts to write the main success scenario first and then its extensions, the alternative and failure paths, because the main path finds the obvious operations and the extensions find everything else.

The nominal path for Verified Resale is short. A fan lists a ticket at Rowmate. Rowmate checks the organizer’s rules and creates the listing. Another fan finds it, passes Bot Screening and buys. Encore reissues the ticket under a new barcode, the new ticket reaches the buyer’s phone, and five days after the event the seller is paid. Walking that path yields the operations everyone expected: read the rules, create a listing, receive an order, learn the reissue result.

The failure paths are where design earns its keep. One question asked at the canvas was simple: what happens when the organizer changes the rules after a ticket is listed? Organizers may only tighten, so the change is always toward fewer listings: a lower cap, a shorter window, resale switched off for the event. A ticket listed at its €60 face value is now above a new €50 cap. Nobody had planned an operation for that moment. Walking the path showed two. Encore needed a way to tell partners the rules had changed, which became a rules.changed event, and it needed a defined fate for listings that no longer complied. The team chose to withdraw them, with the reason rule_change, and let the seller list again within the new rules, which kept the listing lifecycle to its existing six states instead of inventing a seventh.

Path Step Capability Operation
Nominal Fan starts a listing at the partner Check whether a ticket may be listed, and at what price Create a listing with validateOnly
Nominal Fan confirms List the ticket Create a listing
Nominal Another fan buys on the partner’s site Sell a listed ticket to a screened buyer Create an order
Nominal Encore reissues the ticket Learn that the sale completed and what happened to the ticket listing.sold event; read the reissue operation
Alternative Seller changes their mind Take a listing down :withdraw
Failure Organizer lowers the cap after listing Learn that the rules changed, and which listings they affect rules.changed event; listings withdrawn with reason rule_change
Failure Reissue cannot deliver to the buyer’s phone Learn that delivery is delayed, and what Encore is doing Reissue operation reports a failed stage and its retry

Figure 9.2 — Part of the capabilities canvas for Verified Resale’s partner API. The three nominal rows were on the whiteboard before the session began; the failure rows came from walking the paths.

From capabilities to API boundaries

With operations in hand, the next decision is how to group them into APIs. The Architecture book’s Chapter 3 already taught the workshop for this, EventStorming, and the bounded contexts it draws, and we take those contexts as given. What Higginbotham adds is the step from a context to an API boundary, and two ways of getting it wrong. One is the mega-API, a single surface that gathers every capability of several contexts and so couples teams who should change independently. The other is the per-entity API, one API for each noun, which leaves the consumer to orchestrate a dozen calls across surfaces that were never designed to be used together.

For Verified Resale, rules, listings, orders and the operations that track reissue form one Resale API, because a partner uses them together in one journey and they change for the same reasons. Reissue itself stays inside the Inventory team’s internal interface; partners see its progress through an operation resource and never call barcode issuance directly. Separate rule, price and listing APIs would have been the per-entity mistake, and folding resale into a general “tickets API” the mega-API one, since tickets belong to the Ticketing context, which changes on a different rhythm.

The contract as the first deliverable

The Architecture book’s Section 7.1 stated the rule that the contract comes first: the OpenAPI document is written, reviewed and linted before anyone writes the code behind it. This chapter adds one thing to that rule. A contract written first is also something we can hand to a partner first, and for a partner a contract with examples and a mock server behind it is far more useful than a contract alone.

The pieces are standard. The OpenAPI Specification, at version 3.1 since February 2021, can carry worked examples for every request and response, and a mock server, such as Stoplight’s open-source Prism, can serve those examples as though the API were already running. Zalando’s public guidelines open with this principle under the name “API First”, and Lauret and Higginbotham each give a chapter to mocking.

Rowmate integrated against the mock for three weeks before the Resale service reached the sandbox. In those three weeks its engineers found two things that would have been expensive later. The listing response gave the face value and the cap, but not the all-in price a buyer would pay including the 10% fee, so Rowmate’s checkout would have had to compute Encore’s fee itself and would one day have computed it wrongly. And the validateOnly response said only “accepted” or “rejected”, where Rowmate needed the rule that caused a rejection in order to tell the fan what to change. Both were fixed with an edit to the contract. Found in production, either would have been a migration.

Publishers know this economy well. An author corrects galley proofs before the print run, because a change on the galley costs a pencil mark and a change after printing costs a reprint. The mock is a galley that the partner’s code reads. The analogy breaks in a way that matters: a galley cannot drift from the book it previews, but a mock can drift from the service it imitates, and then the partner learns the wrong contract with great confidence. So Encore generates the mock from the contract and runs the same examples as tests against the real service on every build. Contract tests and simulators as engineering practice belong to the Software book’s Section 3.3.

The consumer in the room

Section 3.3 recruited six promoters as design partners for Verified Resale, following Marty Cagan’s customer discovery program, and gave Rowmate a separate, smaller partner program of its own. For an API, a partner’s most useful work is to review the contract while it is still a draft. Rowmate and Tessera both reviewed it before it was built; Tessera had not yet committed to integrate, which made its review more candid.

What makes such a review last is the record it leaves. Every change a partner asked for was written into a decision log that lives beside the contract, with the request, the reason and the answer, much like the entries of an architecture decision record. Tessera asked for a reason code on every withdrawal, so that its sellers would know whether they or the organizer had taken a listing down, and the contract gained an open set of reasons. Rowmate asked for idempotency on listing creation, which the Architecture book’s patterns already required, and the log notes that the request confirmed an existing rule.

The refusals matter as much. Rowmate asked to see how fast an event was selling, so it could advise sellers on pricing. The answer was no, because sales velocity is confidential at Encore, and partners never see it; the fifth fairness invariant says so. The log records the request, the refusal and the reason, so that when a different partner asks the same question a year later, a new product manager finds the answer and its reasoning already written down.

Recap. Designing from the outside in starts with the consumer’s situation, written as job stories and turned into capabilities before any endpoint is named. Walking the failure paths, an old practice from use-case analysis, finds operations that the nominal path never shows, and grouping operations by bounded context avoids both the mega-API and the per-entity API. A contract with examples and a mock lets partners build before the code exists, provided the mock is generated from the contract and tested against the service, and design partners’ requests, granted or refused, belong in a written log.

Exercise 9.1. Write three job stories for an API you own, each from a different consumer’s situation. For each, find the existing operation that serves it. Where none does, or where the consumer would need three calls to do one thing, write down the operation the job story implies, and ask one real consumer whether you have their situation right.

9.2 Patterns That Last

A catalogue, adopted once

Every organization that builds APIs eventually holds the same arguments many times over. How does a client update two fields without sending the whole resource? What does an operation that takes four minutes return? Each question has several defensible answers, and in an organization of 40 teams each team will find a different one unless something stops it, so that a partner who learns how one team handles a long operation must learn again for the next.

Civil engineering solved a version of this problem long ago with standard details. A highway authority publishes standard drawings for a curb, a manhole, a guardrail end and a drainage inlet, and a designer on a new road uses them instead of drawing new ones. The designer’s attention goes to what is particular to the site, its grades and soils and junctions, while the parts that should be the same everywhere are the same everywhere. The analogy holds well, with one difference worth naming. A badly drawn manhole is a problem in each place it is built, but each manhole stands alone. An API pattern is something consumers write code against, so a mistake in a standard pattern is copied into every API that adopts it, and consumers come to depend on the mistake. A pattern catalogue therefore needs the same versioning discipline as an API.

The best public model is Google’s API Improvement Proposals (AIPs), published at google.aip.dev from 2019 onward. Each AIP describes one pattern, gives its reasons and examples, and is numbered so that a design review can say “follow AIP-134” and mean something precise. JJ Geewax, who worked on them, set out the same patterns in book form in API Design Patterns (2021). Microsoft and Zalando publish guidelines of their own, and Zalando marks every rule with its strength, MUST, SHOULD or MAY, and enforces many of them with its open-source linter, Zally. Each shows the same move: decide the pattern once, write it down with its reason, and stop deciding it again.

Encore’s catalogue starts from what the Architecture book’s Section 7.1 already fixed: problem-details errors under Request for Comments (RFC) 9457, idempotency keys on every operation that creates or moves money, and cursor pagination. It adds the patterns in Figure 9.3. One choice in it is a deliberate refusal. Google’s AIP-160 defines a full filter grammar, with expressions such as state = "LISTED" AND price < 60, and it is real and well specified, but it is costly to implement in every service and most partners never need it. Encore’s catalogue chose simple equality filters on named query parameters and recorded the reason, so that the question will not need to be asked again until a consumer’s job story demands more.

Problem Pattern in Encore’s catalogue Example Source
Errors a client can act on Problem details with a stable code and “whose move it is” 422 with code cap_exceeded Architecture book, Section 7.1; RFC 9457
Retrying without doing twice Idempotency-Key on every create Creating a listing Architecture book, Section 7.1
Lists that change while read Opaque cursor, capped page size Listing changes feed Architecture book, Section 7.1
Verbs on an existing resource Custom method, POST with a colon POST /v2/listings/{id}:withdraw AIP-136
Changing some fields JSON Merge Patch; JSON Patch for arrays Lowering a cap RFC 7396; RFC 6902
Work that takes minutes Operation resource with progress and result Reissue AIP-151
“Would this succeed?” validateOnly on the real request Pre-checking a listing AIP-163
Deletes a client may regret Soft delete with expiry and undelete Webhook endpoints AIP-164
Narrowing a list Equality filters on named parameters ?eventId=…&state=listed Encore’s choice; AIP-160 considered

Figure 9.3 — Encore’s API pattern catalogue, as of the Verified Resale build. The first three rows came from the Architecture book; the rest were added by the Public API team and the API guild.

Standard methods and custom ones

The core of a resource-oriented API is a small set of standard methods, the same five verbs applied to every resource: get one, list many, create, update and delete. Their value is predictability: a partner who has learned how Encore lists events can guess how it lists listings. Some actions do not fit the five verbs. Withdrawing a listing is neither an update, since the caller should not set the state field directly, nor a delete, since the record must remain. Google’s convention, in AIP-136, is a custom method: a POST to the resource’s address, followed by a colon and a verb, such as POST /v2/listings/{id}:withdraw. The colon marks the verb as something other than a sub-resource, and the convention keeps the five standard verbs pure.

The Architecture book’s Section 7.1 gave a different answer to a similar problem. There a seat hold became a workflow resource, POST /holds, with its own identity and lifetime, and the catalogue has to say when each form applies. Encore’s rule is short. A custom method is right for a single step that changes the state of an existing resource and finishes at once: a listing is withdrawn, and that is the whole of it. A workflow resource is right when the process itself has an identity and a lifetime that a consumer may want to read, cancel or audit: a hold that expires in five minutes, an order that passes through payment, a reissue that may take minutes to finish. The test is whether anyone will ever want to ask about the process after it has started. If so, the process deserves a name of its own.

The fragment below shows the two forms side by side in the partner contract. Creating a listing is a standard method that also accepts validateOnly, which the next subsection but one explains, and withdrawing a listing is a custom method.

paths:
  /v2/listings:
    post:
      operationId: createListing
      parameters:
        - {name: validateOnly, in: query, schema: {type: boolean, default: false}}
        - {name: Idempotency-Key, in: header, required: true, schema: {type: string}}
      responses:
        "201": {description: Listing created}
        "200": {description: "validateOnly: would be accepted; nothing created"}
        "422": {description: Breaks an organizer rule; the problem names the rule}
  /v2/listings/{id}:withdraw:
    post:
      operationId: withdrawListing
      responses:
        "200": {description: Listing is now withdrawn, with reason seller_request}

Partial updates

The simplest update is a full replacement: the client sends the whole resource and the server stores it. Suppose an organizer’s system, written last year, updates resale rules by sending the cap and window it knows about. This year the rule set gained a per-fan listing limit. The old client’s full replacement omits it, and the server, doing exactly what it was asked, erases the limit the organizer set last week, with no error and no warning. The principle that prevents this fits in one sentence: an update changes only the fields the client names, so that an old client can never erase a field it does not know.

There are three established ways to name the fields. Google’s APIs use a field mask, an update_mask listing the paths to change, described in AIP-134; it is precise and works best with protocol buffers and gRPC, where a message cannot tell an absent field from an empty one. For HTTP and JSON, the widely used alternative is JSON Merge Patch (RFC 7396, 2014): the client sends a JSON (JavaScript Object Notation) document holding only the fields it wants to change, and the server merges it in. Merge Patch has two known limits, both written into Encore’s catalogue: a null value means “remove this field”, so a field cannot be set to null on purpose, and an array can only be replaced whole. Where a client must change one element of an array, the catalogue points to JSON Patch (RFC 6902, 2013), which sends a list of operations instead of a document.

Encore’s catalogue chose Merge Patch as the default for its HTTP APIs. A large promoter’s system lowering the cap for one event sends PATCH /v2/events/{id}/resale-rules with {"cap": {"amount": 5000, "currency": "EUR"}}, and the window and the per-fan limit are untouched whatever that system knows about them.

Long-running operations

The Architecture book’s Section 7.1 introduced the minimal answer to work that outlasts a request: respond 202 Accepted and return a status resource the client can poll. For a partner integrating against real work, that minimum leaves several questions open. How far along is it? Can I cancel it? If it failed, why, and should I retry? How long can I come back and ask? Google’s AIP-151 answers them with a single resource type, the operation, used across Google Cloud: a resource that represents work in progress, carrying its progress as metadata, a done flag, and either a result or an error once it finishes. Geewax gives the pattern a chapter, and Lauret treats long operations in his.

Reissue is Encore’s clearest case. When a listing sells, the order’s response names an operation, and the operation passes through three stages: the seller’s barcode is revoked and added to the revocation lists that venue scanners hold for offline validation, a new ticket identity is issued to the buyer, and the new ticket is delivered to the buyer’s app, with any wallet pass updated. Most reissues complete in under 30 seconds, and 99% within four minutes; Encore’s listings close two hours before doors precisely so that the slowest of them still finish long before anyone reaches a turnstile. The operation reports its current stage, so a partner can tell its buyer “your ticket is being issued” honestly, and any failed stage with Encore’s retry, so the partner can tell “delayed” from “lost”. Operations are kept for 30 days, for partners reconciling disputes.

Cancellation deserves a precise answer, since AIP-151 allows it but does not require it. A reissue can be cancelled only before its first stage completes. Once the seller’s barcode has been revoked, reversing the reissue needs two people’s approval at Encore, as the Software book’s Section 7.4 describes, so the operation carries a cancellable flag that turns false after the first stage. Offering partners a cancel button that really meant a support case would be a promise Encore could not keep. Figure 9.4 draws the operation’s stages and the moment the flag turns.

The reissue operation When a listing sells, the order's response names a reissue operation, which passes through three stages: revoke, in which the seller's barcode is revoked and joins the revocation lists venue scanners hold for offline validation; issue, in which a new ticket identity and barcode are issued to the buyer; and deliver, in which the new ticket reaches the buyer's app and any wallet pass is updated. A failed stage is retried by Encore and reported as such. Most reissues finish in under 30 seconds and 99 percent within four minutes; listings close two hours before doors. The operation is cancellable only until the first stage completes; after that, reversing a reissue needs two people's approval at Encore. Below, what a partner reads from the operation: its current stage, the cancellable flag, a done flag, and a result or an error once finished; and the events reissue.completed or reissue.failed. Operations are kept for 30 days. WHAT THE PARTNER READS MOST UNDER 30 S · 99% WITHIN 4 MIN FAILED STAGE · RETRY FIRST STAGE DONE EVENTS READS THE OPERATION Order created names the operation STAGE 1 Revoke seller's barcode STAGE 2 Issue new ticket identity STAGE 3 Deliver to the buyer's app Partner e.g. Rowmate ONE RESALE · THE OPERATION THE ORDER NAMES DONE joins the revocation lists gates hold offline new barcode, to the buyer wallet pass updated, if any cancellable: true cancellable: false · reversal needs two approvals at Encore operations/rei_51Vd stage: revoke | issue | deliver cancellable: true, until stage 1 is done done: false while in progress result | error, once done The partner tells its buyer "your ticket is being issued" honestly; a failed stage with its retry reads "delayed", not "lost" reissue.completed | reissue.failed Listings close 2 h before doors, so the slowest reissue ends long before the turnstile. Operations are kept 30 days. Order Stage of the operation Partner What reaches the partner Retry

Figure 9.4 — The reissue operation a sale names. Notice where the cancellable flag turns false: after the first stage, the seller’s barcode is already on the gates’ revocation lists, and undoing the reissue is no longer a partner’s call.

Validation-only requests and undoable deletes

Rowmate’s first job story asked to know at once whether a listing would be accepted. The pattern that answers it is the validation-only request: the client sends the real request with a flag, validateOnly, and the server runs every check it would run for real, then returns the verdict without changing anything. AIP-163 describes it, and Geewax gives it a chapter. Partners call it while a fan fills in the listing form, so the fan learns before pressing the final button that the event’s cap is €50, or that resale for this show closes tomorrow evening.

The pattern has one hard requirement: the validation must run the same code as the real request. A separate, simplified copy of the rules will one day say “accepted” to something the real request rejects. Encore implements validateOnly as a flag that stops the Resale service’s create path just before it writes, so every new organizer rule is honored by validation the day it ships. The verdict is true only of its moment, since the organizer may tighten the rules a minute later, and the partner must still handle a 422 on the real request.

Soft delete is the companion pattern for actions a client may regret. In AIP-164 a deleted resource is marked deleted, hidden from ordinary lists and restorable with an :undelete method for a stated period. Encore applies it to webhook endpoint registrations, where partners asked for it: an endpoint deleted by mistake on a Friday evening can be restored, with its delivery history and signing secret, for seven days. Listings do not need the pattern, because they are never deleted; a withdrawn listing remains a record, readable for reconciliation.

Deciding what compatible means

In April 1964 IBM announced System/360, a family of computers of very different sizes and prices that shared one architecture, so that a program written for one model would run on the others. Compatibility was the product: a customer could outgrow a small machine and move to a larger one without rewriting their programs. Every API provider makes a promise of this kind, written down or not, and Geewax’s chapter on versioning makes the point that compatibility is a choice. A provider can promise perpetual stability, it can promise very little and change freely, or it can version semantically and promise stability within a major version. Each choice suits a different audience, and AIP-180 records Google’s.

Facebook offers a clear public example of the choice written down. At its f8 conference in April 2014 it introduced versioning for its Graph API, with a guarantee that core APIs would remain stable for two years and a 90-day migration window for the “extended” ones. A later changelog clarified that a version lives for two years after the next version is released, a number a partner could plan by.

Encore’s choice is the Architecture book’s Section 7.2: additive change forever, never repurpose a field, tolerant readers on both sides, and a new version only as a last resort. This section adds how the choice is written down. Encore’s partner documentation carries a compatibility page. Removing a field, adding a required input, tightening validation, changing a default and changing the meaning of an event are breaking, and come with 12 months’ notice. Adding a field, an endpoint, an event type or a value to an open enumeration is not, and partners are told in writing that their code must tolerate these.

The resale API forced one subtle entry onto that page. Every change to an organizer’s rules makes some listings invalid that were valid a minute before. Is a lower cap a breaking change? The page answers no, because the contract states that listings are always subject to the organizer’s current rules and defines the rules.changed event and the rule_change withdrawal as the way partners learn of changes. A new kind of rule, which a partner’s code must understand to stay correct, is breaking, and is announced like any other breaking change.

Recap. A pattern catalogue settles recurring design questions once, with reasons, so that 40 teams stop answering them differently. Custom methods carry single-step verbs and workflow resources carry processes with a lifetime. Partial updates change only named fields, so old clients cannot erase new ones. Long-running work becomes an operation with progress, a result and honest cancellation. Validation-only requests run the real code, and the meaning of “compatible” is a written choice, most useful where it settles the hard cases.

Exercise 9.2. List the patterns your APIs use for partial update, long-running work and “would this succeed?” checks. Count how many variants of each exist across your teams, and for one pattern, write the catalogue entry that would end the variation: the problem, the chosen pattern, its reason, an example and the source you took it from.

9.3 Consistency Across 40 Teams

A style guide people read

In April 1893 Horace Hart, the Controller of the Oxford University Press, had a small booklet of Rules for Compositors and Readers printed and given to the press’s own staff. Its purpose was that books set by many hands, for many authors, should read as though one house had made them, and it grew edition by edition, as the press wrote down its decisions, into the guide still known as Hart’s Rules. An API style guide is the same instrument for the same purpose: many teams, one surface, and a written record of how things are done here. The analogy breaks at the moment of application. A copy editor applies house style after the author has finished, and a mistake can be corrected in the next printing. An API’s names are published the day it ships, so its style guide has to be applied before release, by tools as far as possible.

Higginbotham gives a chapter to establishing an API style guide, and Lauret’s second edition gives a part of the book to design guidelines. They agree on what makes a guide read. It is short enough to read in an hour. Every rule carries its reason, because a rule without one is broken at the first inconvenience, and an example, good and bad. The guide is versioned, and owned by a small group with the authority to change it. Zalando, Microsoft, Google and PayPal publish theirs openly, and reading two or three is the fastest way to see what a good one looks like. The Architecture book’s Section 7.5 told of one such guide, 89 rules written RFC-style; this section is about keeping one alive.

Encore’s guide is owned by the Public API team, with an API guild drawn from the dozen or so teams that publish partner or public surfaces, and has 71 rules at its current version. It opens with a glossary, because vocabulary is where inconsistency starts and where the Architecture book’s bounded contexts reach the API. Eric Evans called it ubiquitous language in Domain-Driven Design (2003): a context’s words, used the same way in conversation, code and interface. The glossary defines once the terms partners meet: a listing is an offer to resell one ticket; a reissue is the replacement of a sold ticket with a new identity and barcode for its buyer; face value is the price at the primary sale. It also records words that change meaning across contexts. Inside Support a “ticket” is a case; in every partner-facing API a ticket is the right to enter a venue. Google keeps a glossary of the same kind as AIP-9.

Lint rules and their lifecycle

The Architecture book’s Section 7.5 made the case that governance should ship as linting, with Spectral-style rules running in continuous integration (CI) against every contract change, and its Section 7.2 added the breaking-change differ. This subsection takes that as settled and turns to something those sections left out: rules have lives of their own. They are proposed, tried, enforced, excepted and eventually retired, and a guide that has no process for each of those stages grows rigid in some places and ignored in others.

Encore’s guild runs the lifecycle in the open. Anyone may propose a rule, in a pull request to the guide, with the problem it solves, a reason, an example and either a lint implementation or, where a linter cannot check it, an item for the review checklist. “Paths name resources as nouns” can be linted. “Names use the consumer’s words” cannot, and becomes a question the reviewer asks. Of Encore’s 71 rules, 58 are linted and 13 are checklist items. A new linted rule runs as a warning for a month, so the guild can count how many existing contracts it would fail and read why, before it becomes an error that fails builds.

Exceptions are declared in the contract itself and approved in the pull request, never granted in a side conversation, and the guild counts them every month by rule. The record is small:

# In the contract: one entry per exception, read by Encore's lint step
x-encore-lint-exceptions:
  - rule: list-pagination-cursor          # guide rule P-3
    path: /v2/events/{id}/price-levels
    reason: "Fixed list of at most 12 items; a cursor adds work and no value."
    approved-in: "Partner APIs PR, reviewed by the API guild"
    expires: "next major version of the guide"

Counting exceptions turns them into evidence about the rules. Last quarter the guild recorded 37 exceptions, 21 of them against the cursor-pagination rule, nearly all for short, fixed lists like price levels. That was the guide being wrong, and the rule was amended to exempt lists with a documented maximum of 50 items. Rules also retire: a rule that has prevented nothing for a year, and whose reason no longer applies, is removed the way it was adopted, by pull request with a reason.

Review where it matters

The Architecture book’s Section 7.5 rejected design review boards, for good reason: a board that reads every design in a meeting is slow, depends on who attends and turns its members into gatekeepers, and the DORA research cited in the Resilience book’s Section 1.3 found that approval by bodies outside the team slows delivery without making it safer. But linting cannot ask whether an API’s words are the consumer’s words, whether an operation belongs in this boundary or the next, or what happens on the failure path. Some human review is worth having. The question is how to have it without rebuilding the board.

The evidence here is practitioner experience and published company practice. Zalando’s guidelines describe API review by a guild, and Mehdi Medjaoui and his co-authors, in Continuous API Management (second edition, 2021), argue for deciding explicitly which decisions are centralized. Encore reviews only new partner or public surfaces and breaking changes in them; everything internal and every additive change passes on lint alone. Two guild members on a rota review asynchronously in the pull request, against a turnaround target of two working days; last quarter they reviewed 23 changes with a median of a day and a half. They may block only for a broken rule, and anything else is advice the team may decline in writing.

Seeing the landscape

Past a certain size, an organization stops having APIs and starts having an API landscape, with properties no single API has. Medjaoui and his co-authors give a chapter to landscapes and offer eight aspects to watch, all beginning with V: variety, vocabulary, volume, velocity, vulnerability, visibility, versioning and volatility. The eight V’s are one book’s framework, not an industry standard, and Encore uses them only as a checklist of questions to ask each quarter.

The proven part of landscape governance is plainer: a catalogue that lists every API with its owner, tier and lifecycle stage. Backstage’s software catalog has an API entity kind for exactly this, and many organizations keep the same records in other tools. The Architecture book’s Section 7.5 required every endpoint to be born with an owner, tier, objective and deprecation policy, and the Software book’s Section 6.3 makes each service’s manifest the source of the catalogue. This section adds the landscape view: looking at the catalogue as a whole to see what no single entry shows.

Aspect The question Encore asks Encore at month 9
Volume How many APIs, and of which exposure? 268 in the catalogue: 214 internal, 31 partner, 23 public
Variety How many ways do we solve the same problem? Long-running work: one pattern in new APIs, three in older ones
Vocabulary Do teams use the glossary’s words? Four partner APIs still say ticket for a support case
Versioning How many versions are live, and how old is the oldest? Two major versions; the oldest partner version is four years old
Visibility Can a partner or a team find what exists? Partner and public APIs in the portal; 9 internal APIs missing from the catalogue
Volatility Which APIs change most, and do their consumers know? The Resale API, by design, during the build; announced in the changelog
Vulnerability Which APIs expose personal data or money? 11 partner APIs touch payments, orders or fan data
Velocity How long from design to a published contract? Median 19 days for partner APIs, including review

Figure 9.5 — Encore’s API landscape as the guild reviewed it at month 9 of Verified Resale. The numbers matter less than the habit of asking each question every quarter.

The landscape view is where orphans show up. Four internal APIs in the catalogue had owners who had moved teams, and nobody had noticed, because the APIs still worked. An orphaned API is harmless until the day it needs to change, and the catalogue’s job is to make sure that day does not also start the search for whoever owns it.

Recap. A style guide is read when it is short, gives a reason and an example for every rule, carries a glossary of the domain’s words and is owned by a small group that can change it. Lint rules have a lifecycle, from proposal through a trial as warnings to enforcement, counted exceptions and retirement, and counted exceptions are evidence about the rules. Human review is kept for new partner and public surfaces, with a turnaround target, and a catalogue seen as a landscape shows the drift and the orphans that no single API reveals.

Exercise 9.3. Run your linter over every API contract in your organization and rank the five most violated rules. For each, decide whether the contracts are wrong or the rule is, and write down the evidence. Then find one API in your catalogue whose owner has left, and see how long it takes to find who owns it now.

9.4 Partner and Public APIs

The API as a product

The Architecture book’s Section 7.5 observed that an API with outside users has become a product, and the Software book’s Section 8.3 builds the partner program around it. Continuous API Management sets out the product view in detail, with ten pillars of an API product and a lifecycle of five stages: create, publish, realize, maintain and retire. “Realize”, the period in which a published API starts producing the value it was built for, is the stage teams most often forget.

What this chapter adds is the team. Section 1.3 argued that a product is best led by a trio, a product manager, a designer and a tech lead who share responsibility for value, usability and feasibility. The partner API has its own trio inside the Partner APIs team. Its product manager owns the value proposition for partners: sell resale tickets that are guaranteed to be valid at the door, and earn 4 points of the 10% fee on each. Its designer works on what partners touch: the portal, the documentation, the error messages and the sandbox. Its tech lead owns the contract and its evolution.

The trio’s measures follow the partner’s journey after the first call. They track the days from sandbox credentials to a first sandbox listing, the share of partners who pass certification at the first attempt, the hours of integration work partners report, and the share of listings that fail after a partner showed them to a fan as accepted. That last number is the one Rowmate’s first job story was about, and the trio holds it near zero.

The first month

The Architecture book measured developer experience in minutes to the first successful call, with a target under 10. That number is right for the first afternoon. A partner integration is judged on its first month, when the partner’s engineers move from calling the API to building a product on it, and every gap in the sandbox becomes a question sent to Encore and a day lost waiting.

A sandbox is only useful when its data is realistic. Encore’s resale sandbox holds events with every kind of organizer rule, a sold-out on-sale in progress, and tickets in every state of the listing lifecycle. It also borrows an idea from Stripe, whose testing documentation lists card numbers that always produce a given outcome, such as a decline. Encore’s sandbox has test tickets of the same kind: one whose buyer always fails Bot Screening, one whose organizer tightens the cap 30 seconds after it is listed, and one whose reissue fails at delivery and succeeds on retry. A partner engineer can make each failure happen on demand.

Three artifacts carry the rest of the first month. Software development kits (SDKs) are generated from the contract with OpenAPI Generator, as Higginbotham advises, and carry their own semantic version, because the SDK version is what partners actually pin. A dated changelog records every change to the contract, including the additive ones. And a status page reports the partner API’s health separately from the fan storefront’s. Higginbotham’s chapter on the minimum viable portal describes this set well.

Behind them sits an input partners never see: usage per partner, meaning calls per endpoint, error rates, SDK versions in the field and the last time each partner touched each deprecated field. Medjaoui and his co-authors treat this as the basis of continuous improvement, and it decides when a field can be removed and which partner needs help.

Go-live: what the contract asks a partner to prove

An airline does not let a newly qualified pilot carry passengers on the strength of a licence alone. First comes a check ride, much of it spent on procedures that should never be needed: an engine failure at takeoff, a rejected landing. Partner certification has the same shape. A partner that can create a listing has shown very little; what matters is what its integration does when the rules change, when a webhook arrives twice or when a reissue is late. The analogy breaks on decay. A pilot’s skills fade, so pilots are rechecked on a calendar; a partner’s integration breaks when either side changes, so recertification follows major versions and production signals.

Certification before production access has well-known precedents. Salesforce’s AppExchange security review and Shopify’s app review both stand between a partner and the provider’s customers, and Twitter’s 2012 rules, as we saw at the start of the chapter, required certification for client apps pre-installed on devices. The Software book’s Section 8.3 owns Encore’s certification program and its suite of scenarios: a simulated on-sale, a reissue, a listing that breaks a cap, a webhook outage and a revoked grant. That suite fails a candidate partner that caches prices past an organizer’s cap change. This section owns the other half: the list of behaviors the contract requires, from which the suite’s scenarios are drawn. Partners receive sandbox credentials at once and production credentials only after certification.

Verified Resale partner API: what certification checks (contract v2.4)
[ ] Acts on rules.changed within 5 min; never shows a listing that breaks current rules
[ ] Calls validateOnly before showing a listing as accepted; still handles 422 on create
[ ] Sends an Idempotency-Key on every create; reuses it on retry
[ ] Verifies webhook signatures; rejects timestamps older than 5 min
[ ] Deduplicates events by webhook-id; tolerates events arriving out of order
[ ] Honors 429 and Retry-After; never retries a 422
[ ] Treats unknown enum values (new withdrawal reasons, event types) as non-fatal
[ ] Shows the all-in price, including the 10% fee, before the buyer commits
[ ] Reconciles its listing copy from the changes feed, and on cursor expiry from a full read
[ ] Uses certificate-bound 15-min tokens; holds no long-lived key in any repository

Every line traces to a clause of the contract or the terms, and that is the test of a good checklist: a partner that fails an item can be shown the sentence it broke. The last line exists because of the Rowmate key leak told in the Resilience book’s Section 7.2, which is why partners now authenticate with 15-minute tokens bound to a client certificate.

Deprecation as a campaign

The Architecture book’s Section 7.2 gave the mechanics of retirement: Deprecation and Sunset headers, a migration funnel, and a person on the phone for the last three partners. The Software book’s Section 6.4 shows scheduled brownouts flushing out hidden dependents. This subsection is about the campaign around those mechanics, which is where retirements succeed or fail. Having spent a decade maintaining a widely used open-source library, I have come to believe that a deprecation notice is the least-read document in software, and a retirement that relies on people reading it will not finish.

Twitter’s own retirement of version 1.0 is instructive precisely because it slipped. Version 1.1 shipped on 5 September 2012 with a promise of six months to migrate. In March 2013 Twitter moved the date to 7 May, with blackout tests before it, short planned outages to show developers what would break, and version 1.0 finally returned 410 Gone on 11 June 2013. Salesforce offers a calmer example. Its policy promises at least a year’s notice before retiring an API version, and when it scheduled versions 21.0 to 30.0 for retirement in Summer ‘23, it postponed the date to Summer ‘25 and gave customers a switch to test against the retirement first. Dates slip. A slip announced in advance, with a reason and a new date, costs a provider far less of its partners’ trust than a retirement that takes them by surprise.

Encore’s first campaign of this kind retires the Partner Listings endpoint for link-out resale offers, since keeping it would leave an unverified path beside the verified one. Notice goes out on Verified Resale’s launch day, through the changelog, email to every partner’s technical contacts and a Deprecation header, with a Sunset date 12 months later, as the partner terms require. A weekly dashboard shows each caller’s remaining traffic, a Partner APIs engineer offers each caller help with the migration, two brownouts are scheduled for the last quarter, and the trio’s product manager makes the last calls by phone. At the month-18 review Rowmate has moved entirely. The remaining callers are a handful of small sites that have not applied for Verified Resale, and for them the campaign ends in a clear, early, courteous goodbye.

Terms are part of the contract

We can now return to Twitter’s lesson and apply it. A partner’s contract with Encore has two documents. The OpenAPI document says what may be called and what comes back. The partner terms say how often it may be called, what the partner may do with what it receives, how it must be shown to fans, and how and when any of this may change. Conduct terms, such as no buying of primary inventory, no scraping and the enforcement ladder from warning to termination, are the business of the Software book’s Section 8.3. This subsection covers the terms that shape the API.

Rate limits come first, because limits are where Twitter’s 2012 changes began, and because a limit changes what a partner can build. The Architecture book’s Section 7.3 owns the mechanics: a contractual quota, a token-bucket burst allowance, 429 with a Retry-After header under RFC 9110, and the IETF draft RateLimit and RateLimit-Policy headers, which are still drafts and labelled as such in Encore’s documentation. The terms add the numbers. Each resale partner’s steady quota is set by tier, and during a major on-sale an event-scoped limit applies on top: 20 availability reads a second per event, with a burst of 100, for every partner alike. The figure is published, so a partner can design its product around it before its first on-sale.

Display and data-use rules shape a partner’s product more than its code, as Tweetbot’s $19.99 price showed. Encore’s terms require partners to show the all-in price, including the 10% fee, before a buyer commits, and they limit what a partner may do with a buyer’s personal data.

Change notice is the clause on which everything else rests. Encore’s terms promise 12 months’ notice of any breaking change and name the dated changelog as the channel for notice, on the model of Stripe’s dated versions, which the Architecture book’s Section 7.2 cited. The terms also govern their own amendment. A change that takes something away from partners, such as a lower quota, a narrower data-use clause or a change to the 4-point share, carries the same 12 months’ notice; a change that adds something carries 30 days. One exception covers an active security threat: Encore may act at once and must explain in writing within five working days. Facebook’s two-year guarantee of 2014 was such a promise written down in public; in January 2023 Twitter’s written rule followed its action by a week. Partners can plan around strict terms. They cannot plan around terms that move without warning.

Agents as consumers

AI agents increasingly call APIs as tools, and since Anthropic introduced the Model Context Protocol (MCP) on 25 November 2024 they have had a common protocol for it; OpenAI announced support on 26 March 2025, and in December 2025 the protocol was donated to the Agentic AI Foundation under the Linux Foundation. The practice is young, and its best lesson is the one the Architecture book’s Section 7.5 drew: an agent inherits the contracts, scopes and quotas of any other client. Encore publishes no MCP server for partners. An agent acting for Rowmate uses Rowmate’s certified credentials and limits.

Recap. The partner API is a product with its own trio, judged on the partner’s whole journey rather than its first call. The first month depends on a realistic sandbox with test fixtures that produce failures on demand, generated SDKs versioned apart from the API, a dated changelog, a status page and usage data per partner. Certification checks the behaviors the contract requires, above all on the failure paths, and deprecation is a campaign that plans for its dates to slip. The terms are part of the contract, and the clause that matters most is the one that governs notice, including notice of changes to the terms themselves.

Exercise 9.4. Ask a developer from outside your team to build a working integration in your sandbox in one afternoon, using only your public documentation. Write down every question they had to ask and every failure they could not make happen on demand. Then read your partner terms and find the clause that says how much notice you give before changing them. If there is none, draft it.

9.5 Webhooks and Integrations

What the contract already says

The webhook contract is settled. The Architecture book’s Section 7.1 gave it: signed payloads, at-least-once delivery with backoff, an ID on every event for deduplication, and a replay endpoint. The delivery machinery is a shared platform capability, as the Software book’s Sections 6.3 and 6.4 tell, and the isolation of webhook workers belongs to the Resilience book’s Chapter 5. This section is about what remains: what a partner receives, what it can see, and how it keeps its copy of the world correct.

Thin events or full payloads

A full event, which Stripe calls a snapshot event, carries the state of the resource as it was when the event was emitted. A thin event carries little more than the event’s type and the identifiers of the resources involved, and the receiver fetches the current state when it needs it. Full events save a call. Thin events are current when acted on, hardly ever change shape, and carry less personal data across the internet, since buyer details are fetched under the partner’s scopes.

Stripe now offers both, and its reasoning is public. Thin events arrived with its Meters API in the 2024-09-30 release. For snapshot events, Stripe’s documentation warns that the object “can be stale by the time you process it” and recommends fetching the latest state. That warning is Encore’s reason for choosing thin events. Between the moment a listing sells and the moment a partner processes the event, the reissue may have completed or failed and the organizer may have tightened the rules. Encore’s events, listing.sold, listing.withdrawn, listing.expired, rules.changed, reissue.completed and reissue.failed, are all thin. Their envelope follows the Standard Webhooks format of the next subsection; CloudEvents 1.0, a Cloud Native Computing Foundation (CNCF) specification, suits events that also travel over streams.

A thin listing.sold delivery looks like this. The headers carry the event’s ID, its time and its signature, and the body names the listing and the order and nothing more.

POST /hooks/encore HTTP/1.1
Host: partner.rowmate.example
Content-Type: application/json
webhook-id: evt_01J9ZK6Q4X2M8T
webhook-timestamp: 1767225600
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pX4=

{"type": "listing.sold",
 "data": {"listing": "listings/lst_7Hq2", "order": "orders/ord_93Ka",
          "reissueOperation": "operations/rei_51Vd"}}

A courier who finds nobody at home leaves a card saying a parcel is waiting at the depot, and the recipient collects it there. A thin event is that card. The analogy is exact up to the depot. A depot holds the parcel unchanged until someone collects it, while Encore’s “depot” returns whatever is true at the moment of fetching, which may differ from what prompted the card: a partner that fetches the listing after listing.sold may find it already reissued. That is the point of the design, and the partner’s code must expect state to have moved on. The cost is an extra call for every event, which matters at an on-sale, when hundreds of listings may sell in a minute. Encore sizes those reads as part of the partner API’s capacity and does not count them against the event-scoped availability limit, since a partner fetching an order it was told about is doing exactly what it was asked to do.

Delivery the partner can see

Webhook delivery fails in ways the receiver cannot see: a partner whose endpoint has been returning errors since Tuesday’s deploy knows only that its sales seem quiet. So delivery has to be visible to the partner, in the portal, without a support case. Encore’s partner portal shows, for each endpoint, a delivery log of every attempt with its status code and latency, the retry schedule each failing event is on, the endpoint’s health over the past week, and any events waiting for replay. A partner engineer can resend any event from the log.

A partner should also be able to read the retry schedule before it needs it. Providers publish theirs. Stripe’s documentation says it retries live-mode deliveries “for up to 3 days with an exponential back off”. Shopify’s current documentation describes up to eight retries over four hours, after which the subscription is removed. Encore’s default is in Figure 9.6. Partners may shorten the total window, down to 24 hours, or choose different intervals within bounds, because the shared delivery service made retries configurable per partner, a story the Software book’s Section 6.4 tells.

Encore's webhook retry schedule Time after the event runs left to right, not to scale. Attempt 1 is immediate, and the delivery is logged with its status code and latency. Attempts 2 to 4 come at 30 seconds, 2 minutes and 10 minutes, and the event is marked retrying with its next attempt time. Attempts 5 to 7 come at 30 minutes, 1 hour and 3 hours, and the endpoint's health turns amber in the portal. From attempt 8 onward, delivery is retried every 6 hours; after 24 hours of continuous failure the partner's technical contacts get an email and a portal banner. At 72 hours the endpoint is disabled with notice, and its events are kept for replay for 14 days. Partners may shorten the total window to 24 hours or choose other intervals within bounds. ATTEMPT 8 ONWARD · EVERY 6 H DISABLED Logged Retrying Health amber Email + banner ONE EVENT TO A FAILING ENDPOINT · TIME AFTER THE EVENT, NOT TO SCALE 1 0 2 30 S 3 2 MIN 4 10 MIN 5 30 MIN 6 1 H 7 3 H 24 H 72 H WHAT THE PARTNER SEES status code and latency event marked "retrying", next attempt time shown endpoint health turns amber in the portal, and stays so after 24 h of failure, to technical contacts 72 h: endpoint disabled with notice; events kept for replay for 14 days Partners may shorten the window to 24 h, or choose intervals within bounds What the partner sees in the portal Endpoint disabled at 72 h

Figure 9.6 — Encore’s default webhook retry schedule and what the partner sees at each step: attempt 1 at once, 2–4 at 30 s, 2 min and 10 min, 5–7 at 30 min, 1 h and 3 h, then every 6 h, with contacts told after 24 h and the endpoint disabled with notice at 72 h. A disabled endpoint loses nothing that the 14-day replay window still holds.

Two further practices complete the picture. When a partner registers an endpoint, Encore sends a verification event and activates the endpoint only when it answers correctly, as Slack’s URL verification challenge and Microsoft Graph’s validation token do, so a mistyped URL cannot silently swallow a partner’s events. And Encore formats and signs its deliveries according to the Standard Webhooks specification, version 1.0.0, published in December 2023 by an effort that Svix started with a steering committee from Kong, Zapier, Twilio, Lob, Mux, ngrok and Supabase. It is young and its adoption is still growing, but it standardizes what every provider used to invent separately, the webhook-id, webhook-timestamp and webhook-signature headers and how the signature is computed, so a partner can verify several providers with one library.

Testing integrations

The webhook path is the hardest part of an integration to test, because the partner is the receiver and cannot easily make the sender misbehave. Stripe’s tooling shows what good support looks like. Its command-line tool can forward events to a developer’s laptop with stripe listen and fire specific events with stripe trigger, and its dashboard can send a test event to any registered endpoint. Higginbotham’s chapter on testing places these tools in a broader strategy.

Encore’s sandbox goes one step further, because resale has sequences that single test events cannot reproduce. One scenario, on-sale-rush, sells 2,000 listings in ten minutes, with 1% of events delivered twice and a few out of order. Another tightens an organizer’s cap in the middle of a sale; a third makes a reissue fail at delivery and then succeed. Each is also a recorded fixture, a file of signed events a partner can replay in its own test suite, and certification draws on the same scenarios. A sandbox of this standard is really a simulator, and simulators as products are the subject of the Software book’s Section 3.3.

Inventory feeds and reconciliation

Webhooks tell a partner what changed, quickly and usually reliably. “Usually” is the difficulty. An endpoint is disabled for a weekend, a worker drops an event because of a bug, and the partner’s copy of Encore’s listings drifts without anything in a push-only design noticing. Encore already had inventory feeds for partners, listed in Section 1.2 among the things Verified Resale could reuse. For resale they were upgraded on a proven pattern: an incremental feed of changes read by cursor, backed by a periodic full reconciliation.

The pattern has well-known public examples. Google Calendar’s API gives each client a syncToken with which to fetch only what changed since its last read; when the token is too old, the API answers 410 Gone and the client performs a full sync. Kubernetes controllers list the objects they manage and then watch for changes from that list’s resourceVersion, starting over when the watch falls too far behind. Encore’s GET /v2/listing-changes?cursor=… returns every change since the cursor, in order, and the cursor expires after seven days, after which the partner reads its full set of listings and starts afresh.

Rowmate reconciles hourly and after every rules.changed event, because a rule change can withdraw many listings at once, and those are the moments when a missed event would leave a fan looking at a listing that can no longer be bought. Webhooks are fast and can miss; the feed is slower and does not, so the feed corrects whatever the webhooks missed.

Recap. The webhook contract is settled elsewhere, and so is the shared delivery service; what remains is the partner’s experience of it. Thin events let partners act on current state at the price of one more call. Delivery becomes visible through a per-partner log, a published retry schedule, endpoint verification and notice before disabling, and the young Standard Webhooks format saves partners from verifying each provider differently. Sandboxes that emit realistic failure sequences and recorded fixtures make the receiving side testable, and a cursor-based feed with periodic full reconciliation corrects the drift that webhooks alone cannot detect.

Exercise 9.5. In a sandbox, disable your own webhook endpoint for an hour while events are flowing. Then answer three questions without asking the provider for help. Can you see which events you missed? Can you recover them, by replay or from a feed? And would your system have noticed the gap if you had not caused it yourself?

Kata: Sign Here

Your brief: “Tallyhouse.” Tallyhouse sells electronic signature and contract workflow as a service to about 7,000 businesses in four EU countries, and has 95 engineers in 12 teams. A customer drafts a contract from a template, routes it for internal approval, sends it as an envelope to its signers in order and files the signed copy. Law firms and practice-management systems integrate today by dropping documents into an SFTP folder, SFTP being a file-transfer protocol, and waiting for an email saying whether the envelope went out. Tallyhouse wants to open a partner API to about 300 law firms and practice-management vendors, so that a partner can send and track a client’s contracts from its own system. Three teams already expose five internal APIs with three pagination styles and two incompatible ways of updating a signer’s details. One large practice-management vendor scrapes the web interface because nothing else does what it needs. An envelope takes from a few minutes to several weeks to complete, often must be signed before a deadline such as an offer’s expiry or a filing date, and may stall on data a paralegal can fix, such as a mistyped signer email or a missing signature field. The commercial team has promised partners “the same terms as the big platforms”, which nobody has written down, and some 40 firms still use the SFTP folder every week.

Deliverables:

  1. Capability canvas — Job stories from two kinds of partner, a law firm and a practice-management vendor, for “send a contract for signature from a partner system”. Walk the nominal path and at least three failure paths, including a signer corrected after the envelope has gone out, and list the operations they yield.
  2. Pattern choices — Catalogue entries for the three patterns the API needs most: the envelope as a long-running operation (with its stages, progress and voiding rule), validation-only submission of an envelope before it is sent, and partial update of signer records. Give each a reason and a public source.
  3. Lint rules and their lifecycle — Ten rules for the new API style guide, marking which can be linted and which become review questions, and a one-page process for proposing, trying, excepting and retiring rules across the 12 teams.
  4. Certification checklist — The behaviors a partner must show in the sandbox before receiving production credentials, each traced to a clause of the contract or the terms, and the sandbox fixtures that make each failure happen on demand.
  5. Webhook delivery view — A design for what a partner sees in the portal about its envelope.completed and envelope.declined events: the delivery log, the retry schedule, endpoint health and the notice before disabling. Say whether the events are thin or full, and why.
  6. Terms and retirement — The API terms that the commercial team’s promise should have been: rate limits, notice periods for breaking changes and for changes to the terms themselves, and data-use rules. Then plan the SFTP retirement campaign for the 40 firms, with dated milestones.

Rubric:

Criterion The question to ask yourself
Outside-in design Could each operation be traced back to a job story a real partner would recognize, including the failure paths?
Patterns decided once Would a partner who learned one Tallyhouse team’s API find the next team’s familiar?
Governance without a gate Do the lint rules and review process keep 12 teams consistent without anyone waiting a week for approval?
Certification on failure paths Does certification test what partners do when things go wrong, and can every item be shown to rest on a written clause?
Visible delivery Could a partner whose endpoint failed overnight find out what it missed and recover it without contacting Tallyhouse?
Terms partners can plan around Would the practice-management vendor that scrapes the interface today be able to plan a year of work on the terms you wrote?

Where you now stand

You can now design an API from its consumers’ situations outward, settle recurring design questions once in a catalogue, keep many teams consistent with a style guide, a living rule set and review kept for the surfaces that need it, and run a partner API as a product, with a sandbox, certification, deprecation campaigns and terms written to be planned around. You can also run the webhooks and feeds that keep a partner’s copy of the world honest. Each chapter so far has taken one part of Verified Resale on its own: strategy, discovery, measures, price, design, frontend, phones and now interfaces. Chapter 10 puts them back together. It follows the Verified Resale bet memo from the morning it was written to a staged launch with three organizers, Rowmate and one market, and to the review that asks whether the bet paid. It begins with another launch that let people in a few at a time.

References