BlogSoftware
Designing APIs that integrate cleanly with existing systems
By Micah Ondiwa, Senior Software Engineer 1 min read
Integration is where custom software earns its keep. Clear contracts, idempotent writes and honest error handling make it reliable.
Most organisations do not need one system that does everything. They need the systems they already have to share data reliably. That is what a well-designed API does.
Agree the contract first
Before writing code, agree the resources, fields, formats and error responses with every team that will call the API. Publish it as an OpenAPI description so both sides can generate clients and tests from the same source.
Make writes safe to retry
Networks fail. If a client sends "create invoice" and the response is lost, it will retry. Accept an idempotency key on create requests so a repeated call returns the original result instead of creating a duplicate.
Return errors that a machine can act on
- Use HTTP status codes consistently: 4xx for problems with the request, 5xx for problems on the server.
- Include a stable error code and a human-readable message.
- Validate input at the edge and say exactly which field failed.
Version deliberately
Add fields without breaking existing clients, and only introduce a new version when behaviour must change. Give consumers time to migrate and log who still calls the old version.
Secure and observe
Authenticate every caller, give each integration its own credentials with the minimum permissions, and log request IDs so a single transaction can be traced across systems.
Need two systems to talk to each other? See systems integration and APIs.
About the author
Micah Ondiwa
Senior Software Engineer
Micah Ondiwa writes about software engineering — application architecture, APIs and integration, data and AI-assisted development, and reliable delivery.
