eqixiacEquinix Infrastructure as Code

Customer Portal

Order history, trouble tickets, Smart Hands, work visits, shipments, cross connects, billing and reports.

Scope#

The Customer Portal domain covers the colocation operations APIs: the tasks otherwise done in the Equinix Customer Portal web interface.

AccessorCovers
orderHistory()Search across all order types and their status
troubleTickets(), troubleTicketOrders()Incident tickets
smartHandsRequests()Remote hands: twelve typed order kinds
workVisits()Site access for staff and visitors
shipments()Inbound and outbound shipments, pending storage
crossConnects()Cross connect order, update, deinstall
secureCabinets(), orders(), quotes()Other orders
invoices(), billingAccounts(), billingAccountsSearch()Billing
reports()Report Center: generate, schedule, download
assets(), attachments(), lookups()Asset search, attachments, locations and patch panels
notifications(), unifiedNotifications()Maintenance and incident notifications
supportCases(), supportPlans()Support
digitalLoas()Digital Letter of Authorization

Order model#

An order create returns an order number and no resource body, and the v2 order APIs define no operation that reads the ordered resource. The status of an order is read from order history. The SDK therefore has no crossConnects().list() or workVisits().list(), and the read models that 3.0.0 offered for those resources are removed because no API operation returned them.

SDK method names carry no API version. Where a function needs both a v1 and a v2 API, the client calls both, and the version appears only in the request URL.

Order history#

Java
import com.eqixiac.equinix.customerportal.enums.OrderHistoryProductType;
import com.eqixiac.equinix.customerportal.enums.OrderHistoryStatus;
import com.eqixiac.equinix.customerportal.model.OrderHistoryItem;
import com.eqixiac.equinix.customerportal.model.json.creators.OrderHistorySearchRequest;

OrderHistorySearchRequest request = OrderHistorySearchRequest.builder()
    .filters(OrderHistorySearchRequest.Filters.builder()
        .productTypes(OrderHistoryProductType.TROUBLE)
        .orderStatus(List.of(OrderHistoryStatus.SUBMITTED, OrderHistoryStatus.IN_PROGRESS))
        .ibxs(List.of("DC6", "DC11"))
        .build())
    .page(new OrderHistorySearchRequest.PageRequest(0, 50))
    .build();

for (OrderHistoryItem order : portal.orderHistory().search(request)) {
    System.out.println(order.getOrderNumber() + " " + order.getOrderStatus() + " " + order.getType()
        + " " + order.getIbx() + " created " + order.getCreatedAt());
}

searchPage(request) returns the items with the paging block. The Tickets v2 API has no list operation, so tickets are listed through order history with product type TROUBLE. The live service rejects TROUBLE_TICKET with HTTP 400 EQX-171-1212.

The live service names several order-history fields differently from the specification. The SDK reads both forms: accountNumber and accountName, orderingContacts, and the contact fields firstName, lastName, emailAddress, workPhone. getNotificationContacts(), getTechnicalContacts() and getOrderSource() are new in 4.0.

Trouble tickets#

Java
import com.eqixiac.equinix.customerportal.enums.TicketCode;
import com.eqixiac.equinix.customerportal.model.TroubleTicket;
import com.eqixiac.equinix.customerportal.model.json.creators.TicketNoteRequest;
import com.eqixiac.equinix.customerportal.model.json.creators.TroubleTicketCreateRequest;

String ticketId = portal.troubleTickets().create(
    TroubleTicketCreateRequest.builder(
            TicketCode.CODE_0001_0000,                       // problem code from the Tickets v2 catalogue
            "Link down on cross connect 20012345-A since 02:14 UTC, no light received on our side",
            "2026-11-12T02:14:00Z",                          // when the problem occurred
            "DC6:01:012345")                                 // primary identifier of the affected asset
        .customerReferenceId("INC-48211")
        .build());

TroubleTicket ticket = portal.troubleTickets().getByUuid(ticketId);
portal.troubleTickets().addNote(ticketId, new TicketNoteRequest("Our optic was replaced at 02:40 UTC, still no light"));

The TicketCode constants are the numeric problem codes of the Tickets v2 specification, for example 0001-0000. The Equinix ticket documentation lists the problem category that each code stands for.

Work visits#

Java
import com.eqixiac.equinix.customerportal.model.OrderResponse;
import com.eqixiac.equinix.customerportal.model.json.creators.WorkVisitCage;
import com.eqixiac.equinix.customerportal.model.json.creators.WorkVisitDetails;
import com.eqixiac.equinix.customerportal.model.json.creators.WorkVisitOrderRequest;
import com.eqixiac.equinix.customerportal.model.json.creators.WorkVisitVisitor;

WorkVisitDetails visit = WorkVisitDetails.builder(
        List.of(new WorkVisitCage("DC6:01:012345").accountNumber("123456")),
        "2026-11-20T14:00:00Z",
        "2026-11-20T18:00:00Z",
        List.of(WorkVisitVisitor.nonRegistered("Dana", "Okafor", "Example Networks")))
    .openCabinet(true)
    .build();

OrderResponse order = portal.workVisits().order(
    WorkVisitOrderRequest.builder(visit)
        .description("Replace failed line card, slot 3")
        .customerReferenceId("CHG-10492")
        .build());

workVisits().listLocations() returns the IBXs, cages and cabinets the user may request access to, with the identifiers that the cage argument expects.

Smart Hands and shipments#

smartHandsRequests() has one create method per order kind: equipment install, shipment unpack, move or run jumper cable, cage escort, locate package, pictures and documentation, patch cable install and removal, cage cleanup, cable request and other. Each takes a SmartHandsRequestJson built from the IBX location, the contacts, the schedule and the service details for that kind. listTypes() and listLocations() return the valid kinds and locations.

shipments().orderInbound(...), orderOutbound(...) and orderPendingStorage(...) take typed requests for the three shipment variants. A Smart Hands or shipment order is billable, and the APIs define no dry run for either.

Billing#

Java
import com.eqixiac.equinix.customerportal.model.InvoiceSummary;

Map<String, BigDecimal> totalByCurrency = new TreeMap<>();
for (InvoiceSummary invoice : portal.invoices().summaries().loadAll()) {
    totalByCurrency.merge(invoice.getCurrencyCode().getCurrencyCode(), invoice.getTotalAmount(), BigDecimal::add);
}
totalByCurrency.forEach((currency, total) -> System.out.println(currency + " " + total));

The block totals each currency separately. billingAccounts().downloadInvoiceDocument(...) returns the invoice document as bytes.

Reports#

Java
import com.eqixiac.equinix.customerportal.enums.ReportStatus;
import com.eqixiac.equinix.customerportal.model.Report;

for (Report report : portal.reports().getReports(25, List.of(ReportStatus.SUCCESS), null)) {
    byte[] file = portal.reports().downloadReport(report.getReportId());
    Files.write(Path.of(report.getFileName()), file);
}

generateReport(...) and scheduleReport(...) start report jobs, which is a side effect, so the read-only live tier does not call them.

Service behaviour observed live#

  • Attachments, finance accounts, reports and asset search return their paging block as page (Pagination).
  • Attachments answered 504 and asset search answered 500 with an empty body intermittently on 2026-11-11. The default policy retries both statuses for GET. Asset search is a POST, which the default policy does not retry on a 5xx (Retries).
  • The Digital LOA search requires a non-empty filter.and. The privateBetaAccess and betaTermsAgreement endpoints answered 404.
  • The order-history product-type enum on the live service also contains INBOUND_SHIPMENT and OUTBOUND_SHIPMENT, which the specification lacks.

Worked example: colocation operations walkthrough.