{"openapi":"3.0.3","info":{"title":"Celerlinks Integration API","version":"1.0.0","description":"API for bill payments, transactions, events and tickets. Live and sandbox credentials are isolated. Sandbox supports simulated wallet payments only; no online checkout, vouchers, real provider calls or public ticket purchases. See https://app.celerlinks.com/docs/sandbox and /docs/webhooks."},"servers":[{"url":"https://api.celerlinks.com/api-service","description":"Live — prod_ keys"},{"url":"https://api.celerlinks.com/api-service/sandbox","description":"Sandbox — test_ keys; simulated wallet purchases, events and tickets. See /docs/sandbox for limits."}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An environment-specific secret key: prod_ for live, test_ for sandbox."}}},"paths":{"/products/types":{"get":{"operationId":"product-types","summary":"List product types","description":"Discover the available bill-payment services before selecting a provider.","tags":["Bills"],"security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Request completed; inspect the response status for asynchronous operations.","content":{"application/json":{"example":{"success":true,"message":"Request completed successfully","data":[{"id":1,"name":"Airtime","slug":"airtime"}]}}}},"201":{"description":"Resource created."},"202":{"description":"Payment initialized, awaiting confirmation."},"401":{"description":"Invalid or missing API key."},"403":{"description":"Access denied."},"404":{"description":"Resource not found."},"409":{"description":"An identical request is processing."},"422":{"description":"Validation failed."},"429":{"description":"Rate limit exceeded."}}}},"/products/billers":{"get":{"operationId":"billers","summary":"List billers","description":"Find the networks and providers available for a product type.","tags":["Bills"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"product_type_id","in":"query","required":true,"description":"ID returned by List product types. Send query IDs as strings.","schema":{"type":"string"}}],"responses":{"200":{"description":"Request completed; inspect the response status for asynchronous operations.","content":{"application/json":{"example":{"success":true,"message":"Request completed successfully","data":[{"id":1,"name":"Example provider"}]}}}},"201":{"description":"Resource created."},"202":{"description":"Payment initialized, awaiting confirmation."},"401":{"description":"Invalid or missing API key."},"403":{"description":"Access denied."},"404":{"description":"Resource not found."},"409":{"description":"An identical request is processing."},"422":{"description":"Validation failed."},"429":{"description":"Rate limit exceeded."}}}},"/products/categories":{"get":{"operationId":"categories","summary":"List product categories","description":"Narrow a service by category, optionally filtering by provider.","tags":["Bills"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"product_type_id","in":"query","required":true,"description":"ID returned by List product types. Send query IDs as strings.","schema":{"type":"string"}},{"name":"biller_id","in":"query","required":false,"description":"ID returned by List billers.","schema":{"type":"string"}}],"responses":{"200":{"description":"Request completed; inspect the response status for asynchronous operations.","content":{"application/json":{"example":{"success":true,"message":"Request completed successfully","data":[{"id":1,"name":"Example category"}]}}}},"201":{"description":"Resource created."},"202":{"description":"Payment initialized, awaiting confirmation."},"401":{"description":"Invalid or missing API key."},"403":{"description":"Access denied."},"404":{"description":"Resource not found."},"409":{"description":"An identical request is processing."},"422":{"description":"Validation failed."},"429":{"description":"Rate limit exceeded."}}}},"/products":{"get":{"operationId":"products","summary":"List products","description":"Fetch current product codes and prices. Always use the live catalogue; codes and prices can change.\n\nAirtime top-ups use a product code plus an amount. Data and TV subscriptions use the specific plan’s product code.","tags":["Bills"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"product_type_id","in":"query","required":true,"description":"ID returned by List product types. Send query IDs as strings.","schema":{"type":"string"}},{"name":"biller_id","in":"query","required":false,"description":"ID returned by List billers.","schema":{"type":"string"}},{"name":"product_category_id","in":"query","required":false,"description":"Optional category ID.","schema":{"type":"string"}}],"responses":{"200":{"description":"Request completed; inspect the response status for asynchronous operations.","content":{"application/json":{"example":{"success":true,"message":"Request completed successfully","data":[{"code":"PRODUCT_CODE","name":"Example product","price":1000}]}}}},"201":{"description":"Resource created."},"202":{"description":"Payment initialized, awaiting confirmation."},"401":{"description":"Invalid or missing API key."},"403":{"description":"Access denied."},"404":{"description":"Resource not found."},"409":{"description":"An identical request is processing."},"422":{"description":"Validation failed."},"429":{"description":"Rate limit exceeded."}}}},"/products/validate-recipient":{"post":{"operationId":"validate-recipient","summary":"Validate a recipient","description":"Verify electricity, TV, or education recipient details before purchasing.\n\nThe data object varies by provider. If an access_token is returned, include it in the purchase request. A failed validation returns an error; do not proceed.","tags":["Bills"],"security":[{"bearerAuth":[]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"product_code":{"type":"string","description":"Use the code from the current product catalogue."},"recipient_number":{"type":"string","description":"Phone number, meter number, or smartcard number for the selected product."},"scenario":{"type":"string","description":"Sandbox only: success (default) or failure. Rejected on live routes."}},"required":["product_code","recipient_number"]},"example":{"product_code":"PRODUCT_CODE","recipient_number":"RECIPIENT_NUMBER"}}}},"responses":{"200":{"description":"Request completed; inspect the response status for asynchronous operations.","content":{"application/json":{"example":{"success":true,"message":"Request completed successfully","data":{}}}}},"201":{"description":"Resource created."},"202":{"description":"Payment initialized, awaiting confirmation."},"401":{"description":"Invalid or missing API key."},"403":{"description":"Access denied."},"404":{"description":"Resource not found."},"409":{"description":"An identical request is processing."},"422":{"description":"Validation failed."},"429":{"description":"Rate limit exceeded."}}}},"/products/buy":{"post":{"operationId":"buy-product","summary":"Purchase a product","description":"Buy airtime, data, electricity, TV, or education products from the catalogue.\n\nThis is a live financial request. Send a unique X-Idempotency-Key for each purchase and reuse it only for retries of that exact request. Online payment returns HTTP 202 with data.payment_link; initialization is not confirmation of delivery.","tags":["Bills"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Unique per purchase. Required in sandbox; retained for the life of the sandbox record. Live requests retain it for 24 hours. Reuse only for retries of the exact same request.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"product_code":{"type":"string","description":"Use the code from the current product catalogue."},"recipient_number":{"type":"string","description":"Phone number, meter number, or smartcard number for the selected product."},"scenario":{"type":"string","description":"Sandbox only: success (default), failure, or pending. Rejected on live routes."},"amount":{"type":"number","description":"Amount in NGN for variable-value products such as airtime and electricity."},"payment_method":{"type":"string","description":"wallet or online. Wallet purchases debit your Celerlinks balance."},"pin":{"type":"string","description":"Your four-digit transaction PIN, required for wallet payments when a PIN is set."},"access_token":{"type":"string","description":"Recipient-validation token, if returned by the provider."}},"required":["product_code","recipient_number"]},"example":{"product_code":"PRODUCT_CODE","recipient_number":"RECIPIENT_NUMBER","amount":1000,"payment_method":"wallet","pin":"YOUR_PIN"}}}},"responses":{"200":{"description":"Request completed; inspect the response status for asynchronous operations.","content":{"application/json":{"example":{"success":true,"message":"Request completed successfully","data":{"id":123,"reference":"TRANSACTION_REFERENCE","status":"processing","amount":1000}}}}},"201":{"description":"Resource created."},"202":{"description":"Payment initialized, awaiting confirmation."},"401":{"description":"Invalid or missing API key."},"403":{"description":"Access denied."},"404":{"description":"Resource not found."},"409":{"description":"An identical request is processing."},"422":{"description":"Validation failed."},"429":{"description":"Rate limit exceeded."}}}},"/transactions":{"get":{"operationId":"transactions","summary":"List transactions","description":"Retrieve the authenticated account’s transaction history and pagination metadata.","tags":["Transactions"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","required":false,"description":"Page number.","schema":{"type":"integer"}},{"name":"per_page","in":"query","required":false,"description":"Results per page (maximum 100).","schema":{"type":"integer"}}],"responses":{"200":{"description":"Request completed; inspect the response status for asynchronous operations.","content":{"application/json":{"example":{"success":true,"data":[{"id":123,"reference":"TRANSACTION_REFERENCE","status":"processing","amount":1000}],"meta":{"current_page":1,"last_page":1,"per_page":15,"total":1}}}}},"201":{"description":"Resource created."},"202":{"description":"Payment initialized, awaiting confirmation."},"401":{"description":"Invalid or missing API key."},"403":{"description":"Access denied."},"404":{"description":"Resource not found."},"409":{"description":"An identical request is processing."},"422":{"description":"Validation failed."},"429":{"description":"Rate limit exceeded."}}}},"/transactions/detail/{id}":{"get":{"operationId":"transaction","summary":"Get transaction details","description":"Check a transaction’s status and retrieve available delivery details, including electricity tokens.\n\nOnly transactions owned by your account are accessible. Poll with a delay while pending; avoid tight loops or retrying a purchase with a new idempotency key.","tags":["Transactions"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Numeric transaction ID returned by a purchase or transaction list.","schema":{"type":"integer"}}],"responses":{"200":{"description":"Request completed; inspect the response status for asynchronous operations.","content":{"application/json":{"example":{"success":true,"message":"Request completed successfully","data":{"id":123,"reference":"TRANSACTION_REFERENCE","status":"successful","payment_status":"successful","amount":1000,"token":null,"units":null}}}}},"201":{"description":"Resource created."},"202":{"description":"Payment initialized, awaiting confirmation."},"401":{"description":"Invalid or missing API key."},"403":{"description":"Access denied."},"404":{"description":"Resource not found."},"409":{"description":"An identical request is processing."},"422":{"description":"Validation failed."},"429":{"description":"Rate limit exceeded."}}}},"/my-events":{"get":{"operationId":"my-events","summary":"List your events","description":"Retrieve events managed by the authenticated account.","tags":["Events"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","required":false,"description":"Page number.","schema":{"type":"integer"}}],"responses":{"200":{"description":"Request completed; inspect the response status for asynchronous operations.","content":{"application/json":{"example":{"success":true,"message":"Request completed successfully","data":{"events":{"data":[{"id":123,"title":"Community meetup","status":"draft"}],"current_page":1,"last_page":1,"total":1}}}}}},"201":{"description":"Resource created."},"202":{"description":"Payment initialized, awaiting confirmation."},"401":{"description":"Invalid or missing API key."},"403":{"description":"Access denied."},"404":{"description":"Resource not found."},"409":{"description":"An identical request is processing."},"422":{"description":"Validation failed."},"429":{"description":"Rate limit exceeded."}}}},"/events":{"post":{"operationId":"create-event","summary":"Create an event","description":"Start a draft event. Add tickets and publish when the details are ready.","tags":["Events"],"security":[{"bearerAuth":[]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","description":"Event name, up to 255 characters."},"description":{"type":"string","description":"Event description."},"starts_at":{"type":"string","description":"ISO 8601 start date/time, including timezone offset."},"ends_at":{"type":"string","description":"Must be on or after starts_at."},"timezone":{"type":"string","description":"IANA timezone, for example Africa/Lagos."},"location_type":{"type":"string","description":"physical, virtual, or hybrid."},"venue":{"type":"string","description":"Venue name."},"address":{"type":"string","description":"Venue address."},"city":{"type":"string","description":"City name."},"virtual_url":{"type":"string","description":"Meeting URL for virtual or hybrid events."},"capacity":{"type":"integer","description":"Maximum capacity, at least 1."},"visibility":{"type":"string","description":"public, private, or unlisted."},"require_approval":{"type":"boolean","description":"Whether guests need approval."}},"required":["title"]},"example":{"title":"Community meetup","timezone":"Africa/Lagos","location_type":"physical","venue":"Your venue","visibility":"public"}}}},"responses":{"200":{"description":"Request completed; inspect the response status for asynchronous operations.","content":{"application/json":{"example":{"success":true,"message":"Request completed successfully","data":{"id":123,"title":"Community meetup","status":"draft"}}}}},"201":{"description":"Resource created."},"202":{"description":"Payment initialized, awaiting confirmation."},"401":{"description":"Invalid or missing API key."},"403":{"description":"Access denied."},"404":{"description":"Resource not found."},"409":{"description":"An identical request is processing."},"422":{"description":"Validation failed."},"429":{"description":"Rate limit exceeded."}}}},"/events/{event}":{"put":{"operationId":"update-event","summary":"Update an event","description":"Update an event owned by your account. Omitted fields remain unchanged.","tags":["Events"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"event","in":"path","required":true,"description":"ID of an event owned by this account.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","description":"Event name, up to 255 characters."},"description":{"type":"string","description":"Event description."},"starts_at":{"type":"string","description":"ISO 8601 start date/time, including timezone offset."},"ends_at":{"type":"string","description":"Must be on or after starts_at."},"timezone":{"type":"string","description":"IANA timezone, for example Africa/Lagos."},"location_type":{"type":"string","description":"physical, virtual, or hybrid."},"venue":{"type":"string","description":"Venue name."},"address":{"type":"string","description":"Venue address."},"city":{"type":"string","description":"City name."},"virtual_url":{"type":"string","description":"Meeting URL for virtual or hybrid events."},"capacity":{"type":"integer","description":"Maximum capacity, at least 1."},"visibility":{"type":"string","description":"public, private, or unlisted."},"require_approval":{"type":"boolean","description":"Whether guests need approval."}}},"example":{"title":"Updated community meetup"}}}},"responses":{"200":{"description":"Request completed; inspect the response status for asynchronous operations.","content":{"application/json":{"example":{"success":true,"message":"Request completed successfully","data":{"id":123,"title":"Updated community meetup"}}}}},"201":{"description":"Resource created."},"202":{"description":"Payment initialized, awaiting confirmation."},"401":{"description":"Invalid or missing API key."},"403":{"description":"Access denied."},"404":{"description":"Resource not found."},"409":{"description":"An identical request is processing."},"422":{"description":"Validation failed."},"429":{"description":"Rate limit exceeded."}}}},"/events/{event}/publish":{"post":{"operationId":"publish-event","summary":"Publish an event","description":"Publish your draft after completing its required details.","tags":["Events"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"event","in":"path","required":true,"description":"ID of an event owned by this account.","schema":{"type":"string"}}],"responses":{"200":{"description":"Request completed; inspect the response status for asynchronous operations.","content":{"application/json":{"example":{"success":true,"message":"Request completed successfully","data":[]}}}},"201":{"description":"Resource created."},"202":{"description":"Payment initialized, awaiting confirmation."},"401":{"description":"Invalid or missing API key."},"403":{"description":"Access denied."},"404":{"description":"Resource not found."},"409":{"description":"An identical request is processing."},"422":{"description":"Validation failed."},"429":{"description":"Rate limit exceeded."}}}},"/events/{event}/ticket-types":{"post":{"operationId":"create-ticket","summary":"Create a ticket type","description":"Add a free or paid ticket type to your event.","tags":["Tickets"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"event","in":"path","required":true,"description":"ID of an event owned by this account.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Ticket name; up to 255 characters."},"price":{"type":"number","description":"Price in NGN, not kobo. Use 0 for free admission."},"quantity":{"type":"integer","description":"Number of tickets available; minimum 1."},"description":{"type":"string","description":"Optional ticket description."},"sales_start":{"type":"string","description":"ISO 8601 date/time."},"sales_end":{"type":"string","description":"Must be later than sales_start."},"min_per_order":{"type":"integer","description":"Minimum tickets per order; at least 1."},"max_per_order":{"type":"integer","description":"At least min_per_order."}},"required":["name","price"]},"example":{"name":"General admission","price":5000,"quantity":100}}}},"responses":{"200":{"description":"Request completed; inspect the response status for asynchronous operations.","content":{"application/json":{"example":{"success":true,"message":"Request completed successfully","data":{"ticket_type":{"id":456,"name":"General admission","price":5000}}}}}},"201":{"description":"Resource created."},"202":{"description":"Payment initialized, awaiting confirmation."},"401":{"description":"Invalid or missing API key."},"403":{"description":"Access denied."},"404":{"description":"Resource not found."},"409":{"description":"An identical request is processing."},"422":{"description":"Validation failed."},"429":{"description":"Rate limit exceeded."}}}},"/ticket-types/{ticketType}":{"put":{"operationId":"update-ticket","summary":"Update a ticket type","description":"Edit a ticket type. Quantity cannot fall below tickets already sold or reserved.","tags":["Tickets"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"ticketType","in":"path","required":true,"description":"ID of a ticket type belonging to your event.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Ticket name; up to 255 characters."},"price":{"type":"number","description":"Price in NGN, not kobo. Use 0 for free admission."},"quantity":{"type":"integer","description":"Number of tickets available; minimum 1."},"description":{"type":"string","description":"Optional ticket description."},"sales_start":{"type":"string","description":"ISO 8601 date/time."},"sales_end":{"type":"string","description":"Must be later than sales_start."},"min_per_order":{"type":"integer","description":"Minimum tickets per order; at least 1."},"max_per_order":{"type":"integer","description":"At least min_per_order."}},"required":["name","price"]},"example":{"name":"General admission","price":5000,"quantity":150}}}},"responses":{"200":{"description":"Request completed; inspect the response status for asynchronous operations.","content":{"application/json":{"example":{"success":true,"message":"Request completed successfully","data":{"ticket_type":{"id":456,"name":"General admission","price":5000,"quantity":150}}}}}},"201":{"description":"Resource created."},"202":{"description":"Payment initialized, awaiting confirmation."},"401":{"description":"Invalid or missing API key."},"403":{"description":"Access denied."},"404":{"description":"Resource not found."},"409":{"description":"An identical request is processing."},"422":{"description":"Validation failed."},"429":{"description":"Rate limit exceeded."}}},"delete":{"operationId":"delete-ticket","summary":"Delete a ticket type","description":"Remove a ticket type. Ticket types with existing sales cannot be deleted.","tags":["Tickets"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"ticketType","in":"path","required":true,"description":"ID of a ticket type belonging to your event.","schema":{"type":"string"}}],"responses":{"200":{"description":"Request completed; inspect the response status for asynchronous operations.","content":{"application/json":{"example":{"success":true,"message":"Request completed successfully","data":[]}}}},"201":{"description":"Resource created."},"202":{"description":"Payment initialized, awaiting confirmation."},"401":{"description":"Invalid or missing API key."},"403":{"description":"Access denied."},"404":{"description":"Resource not found."},"409":{"description":"An identical request is processing."},"422":{"description":"Validation failed."},"429":{"description":"Rate limit exceeded."}}}},"/transactions/{id}/simulate":{"post":{"operationId":"simulate-transaction","summary":"Complete a pending sandbox transaction","servers":[{"url":"https://api.celerlinks.com/api-service/sandbox"}],"tags":["Sandbox"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["successful","failed"]}}},"example":{"status":"successful"}}}},"responses":{"200":{"description":"Sandbox status updated and matching webhooks queued."},"401":{"description":"Sandbox API key required."},"404":{"description":"Transaction not owned by this account."},"409":{"description":"Transaction is already final."}}}}}}