A customer submits a support request through a portal. The ticket may already exist by the time the browser reports a timeout. Now the customer presses Submit again. Should the second attempt return the original ticket number or create another ticket? A team building the whole portal can settle that inside the application. Give a mobile app or a partner access to the same workflow and the answer becomes part of a contract.
Write down what clients can rely on
Start with one operation, such as POST /support-tickets. Agree on which fields a caller supplies, who can open a ticket for an organisation, and what the server returns. Designing the API first gives the people building the endpoint and the people calling it a chance to resolve those questions before either side ships.
OpenAPI describes HTTP operations, inputs, responses and security requirements in a standard format. The team still has to implement and test the permission checks. A valid token alone tells the server little about whether this particular caller can open a ticket for the organisation named in the request.
Then consider what happens after release. If an older app expects ticketId, renaming the field to id may break it before users can update. A compatibility check can catch the missing field before deployment. Someone also needs to own the decision to retire it and give consumers time to migrate. GitHub uses date-based REST API versions for breaking changes. For a small portal, keeping both fields available during a migration may be enough.
Put the network boundary where clients need it
With one team shipping a server-rendered portal, the form handler can call a ticket module inside the application. Define the inputs and failure cases at that boundary. Adding an HTTP hop inside that workflow means deciding how to handle a slow or interrupted call, so ask which dependency the hop is meant to serve.
If an independently released mobile app arrives, the portal backend can expose an HTTP endpoint backed by that same ticket module. The app gets a stable interface and can ship on its own schedule. The backend can still deploy as one application. A separate ticket service becomes a decision in its own right when there is a reason to release or operate it independently.
Decide what happens on the second attempt
A timeout tells the client it did not get a response in time. The server may have saved the ticket already. If the client can retry automatically, one option is to have it send the same idempotency key for the same attempt. Once the first attempt has finished, the server can use that key to return the original ticket number. The contract should also cover concurrent requests and the case where a caller reuses a key with different inputs.
Stripe’s API v1 documents a concrete implementation. It compares parameters when a key is reused and can remove keys once they are at least 24 hours old. Reusing a pruned key starts a new request. Set the portal’s retention period according to how long its clients are allowed to retry.
Test the case that prompted the design. Let the backend save the ticket, interrupt the response, then send the same request again. Check the ticket number the client receives and count the records in storage. Both observations matter when the portal and mobile app start shipping on different schedules.
Sources
Contact us
Tell us how we can help; we will respond within two working days.

